diff --git a/java-analysis-impl/src/main/java/com/intellij/java/analysis/impl/codeInsight/daemon/impl/analysis/AnnotationsHighlightUtil.java b/java-analysis-impl/src/main/java/com/intellij/java/analysis/impl/codeInsight/daemon/impl/analysis/AnnotationsHighlightUtil.java index ad109c4b0..323d5cc4a 100644 --- a/java-analysis-impl/src/main/java/com/intellij/java/analysis/impl/codeInsight/daemon/impl/analysis/AnnotationsHighlightUtil.java +++ b/java-analysis-impl/src/main/java/com/intellij/java/analysis/impl/codeInsight/daemon/impl/analysis/AnnotationsHighlightUtil.java @@ -27,7 +27,9 @@ import com.intellij.java.language.psi.util.ClassUtil; import com.intellij.java.language.psi.util.PsiUtil; import com.intellij.java.language.psi.util.TypeConversionUtil; +import consulo.annotation.access.RequiredReadAction; import consulo.codeEditor.Editor; +import consulo.java.language.impl.localize.JavaErrorLocalize; import consulo.java.language.module.util.JavaClassNames; import consulo.language.editor.intention.IntentionAction; import consulo.language.editor.intention.QuickFixAction; @@ -38,6 +40,7 @@ import consulo.language.psi.*; import consulo.language.psi.util.PsiTreeUtil; import consulo.language.util.IncorrectOperationException; +import consulo.localize.LocalizeValue; import consulo.logging.Logger; import consulo.project.Project; import consulo.util.lang.Comparing; @@ -45,6 +48,7 @@ import jakarta.annotation.Nonnull; import jakarta.annotation.Nullable; + import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.HashSet; @@ -57,820 +61,895 @@ * @author ven */ public class AnnotationsHighlightUtil { - private static final Logger LOG = Logger.getInstance(AnnotationsHighlightUtil.class); + private static final Logger LOG = Logger.getInstance(AnnotationsHighlightUtil.class); + + @Nullable + @RequiredReadAction + public static HighlightInfo checkNameValuePair(PsiNameValuePair pair) { + PsiReference ref = pair.getReference(); + if (ref == null) { + return null; + } + PsiMethod method = (PsiMethod)ref.resolve(); + if (method == null) { + if (pair.getName() != null) { + return HighlightInfo.newHighlightInfo(HighlightInfoType.WRONG_REF) + .range(ref.getElement()) + .descriptionAndTooltip(JavaErrorLocalize.annotationUnknownMethod(ref.getCanonicalText())) + .registerFix(QuickFixFactory.getInstance().createCreateAnnotationMethodFromUsageFix(pair)) + .create(); + } + else { + HighlightInfo highlightInfo = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(ref.getElement()) + .descriptionAndTooltip(JavaErrorLocalize.annotationMissingMethod(ref.getCanonicalText())) + .create(); + for (IntentionAction action : QuickFixFactory.getInstance().createAddAnnotationAttributeNameFixes(pair)) { + QuickFixAction.registerQuickFixAction(highlightInfo, action); + } + return highlightInfo; + } + } + else { + PsiType returnType = method.getReturnType(); + assert returnType != null : method; + PsiAnnotationMemberValue value = pair.getValue(); + HighlightInfo info = checkMemberValueType(value, returnType); + if (info != null) { + return info; + } - @Nullable - public static HighlightInfo checkNameValuePair(PsiNameValuePair pair) { - PsiReference ref = pair.getReference(); - if (ref == null) { - return null; + return checkDuplicateAttribute(pair); + } } - PsiMethod method = (PsiMethod) ref.resolve(); - if (method == null) { - if (pair.getName() != null) { - final String description = JavaErrorBundle.message("annotation.unknown.method", ref.getCanonicalText()); - PsiElement element = ref.getElement(); - final HighlightInfo highlightInfo = HighlightInfo.newHighlightInfo(HighlightInfoType.WRONG_REF).range(element).descriptionAndTooltip(description).create(); - QuickFixAction.registerQuickFixAction(highlightInfo, QuickFixFactory.getInstance().createCreateAnnotationMethodFromUsageFix(pair)); - return highlightInfo; - } else { - String description = JavaErrorBundle.message("annotation.missing.method", ref.getCanonicalText()); - PsiElement element = ref.getElement(); - final HighlightInfo highlightInfo = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(element).descriptionAndTooltip(description).create(); - for (IntentionAction action : QuickFixFactory.getInstance().createAddAnnotationAttributeNameFixes(pair)) { - QuickFixAction.registerQuickFixAction(highlightInfo, action); - } - return highlightInfo; - } - } else { - PsiType returnType = method.getReturnType(); - assert returnType != null : method; - PsiAnnotationMemberValue value = pair.getValue(); - HighlightInfo info = checkMemberValueType(value, returnType); - if (info != null) { - return info; - } - - return checkDuplicateAttribute(pair); + + @Nullable + @RequiredReadAction + private static HighlightInfo checkDuplicateAttribute(PsiNameValuePair pair) { + PsiAnnotationParameterList annotation = (PsiAnnotationParameterList)pair.getParent(); + PsiNameValuePair[] attributes = annotation.getAttributes(); + for (PsiNameValuePair attribute : attributes) { + if (attribute == pair) { + break; + } + String name = pair.getName(); + if (Comparing.equal(attribute.getName(), name)) { + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(pair) + .descriptionAndTooltip(JavaErrorLocalize.annotationDuplicateAttribute( + name == null ? PsiAnnotation.DEFAULT_REFERENCED_METHOD_NAME : name + )) + .create(); + } + } + + return null; } - } - - @Nullable - private static HighlightInfo checkDuplicateAttribute(PsiNameValuePair pair) { - PsiAnnotationParameterList annotation = (PsiAnnotationParameterList) pair.getParent(); - PsiNameValuePair[] attributes = annotation.getAttributes(); - for (PsiNameValuePair attribute : attributes) { - if (attribute == pair) { - break; - } - String name = pair.getName(); - if (Comparing.equal(attribute.getName(), name)) { - String description = JavaErrorBundle.message("annotation.duplicate.attribute", name == null ? PsiAnnotation.DEFAULT_REFERENCED_METHOD_NAME : name); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(pair).descriptionAndTooltip(description).create(); - } + + @RequiredReadAction + private static String formatReference(PsiJavaCodeReferenceElement ref) { + return ref.getCanonicalText(); } - return null; - } + @Nullable + @RequiredReadAction + public static HighlightInfo checkMemberValueType(@Nullable PsiAnnotationMemberValue value, PsiType expectedType) { + if (value == null) { + return null; + } - private static String formatReference(PsiJavaCodeReferenceElement ref) { - return ref.getCanonicalText(); - } + if (expectedType instanceof PsiClassType && expectedType.equalsToText(JavaClassNames.JAVA_LANG_CLASS)) { + if (!(value instanceof PsiClassObjectAccessExpression)) { + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(value) + .descriptionAndTooltip(JavaErrorLocalize.annotationNonClassLiteralAttributeValue()) + .create(); + } + } - @Nullable - public static HighlightInfo checkMemberValueType(@Nullable PsiAnnotationMemberValue value, PsiType expectedType) { - if (value == null) { - return null; - } + if (value instanceof PsiAnnotation annotation) { + PsiJavaCodeReferenceElement nameRef = annotation.getNameReferenceElement(); + if (nameRef == null) { + return null; + } - if (expectedType instanceof PsiClassType && expectedType.equalsToText(JavaClassNames.JAVA_LANG_CLASS)) { - if (!(value instanceof PsiClassObjectAccessExpression)) { - String description = JavaErrorBundle.message("annotation.non.class.literal.attribute.value"); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(value).descriptionAndTooltip(description).create(); - } - } + if (expectedType instanceof PsiClassType expectedClassType) { + PsiClass aClass = expectedClassType.resolve(); + if (aClass != null && nameRef.isReferenceTo(aClass)) { + return null; + } + } - if (value instanceof PsiAnnotation) { - PsiJavaCodeReferenceElement nameRef = ((PsiAnnotation) value).getNameReferenceElement(); - if (nameRef == null) { - return null; - } + if (expectedType instanceof PsiArrayType expectedArrayType + && expectedArrayType.getComponentType() instanceof PsiClassType componentClassType) { + PsiClass aClass = componentClassType.resolve(); + if (aClass != null && nameRef.isReferenceTo(aClass)) { + return null; + } + } - if (expectedType instanceof PsiClassType) { - PsiClass aClass = ((PsiClassType) expectedType).resolve(); - if (aClass != null && nameRef.isReferenceTo(aClass)) { - return null; + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(value) + .descriptionAndTooltip(JavaErrorLocalize.incompatibleTypes( + JavaHighlightUtil.formatType(expectedType), + formatReference(nameRef) + )) + .create(); } - } - if (expectedType instanceof PsiArrayType) { - PsiType componentType = ((PsiArrayType) expectedType).getComponentType(); - if (componentType instanceof PsiClassType) { - PsiClass aClass = ((PsiClassType) componentType).resolve(); - if (aClass != null && nameRef.isReferenceTo(aClass)) { - return null; - } + if (value instanceof PsiArrayInitializerMemberValue) { + if (expectedType instanceof PsiArrayType) { + return null; + } + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(value) + .descriptionAndTooltip(JavaErrorLocalize.annotationIllegalArrayInitializer(JavaHighlightUtil.formatType(expectedType))) + .create(); } - } - String description = JavaErrorBundle.message("incompatible.types", JavaHighlightUtil.formatType(expectedType), formatReference(nameRef)); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(value).descriptionAndTooltip(description).create(); - } + if (value instanceof PsiExpression expr) { + PsiType type = expr.getType(); - if (value instanceof PsiArrayInitializerMemberValue) { - if (expectedType instanceof PsiArrayType) { - return null; - } - String description = JavaErrorBundle.message("annotation.illegal.array.initializer", JavaHighlightUtil.formatType(expectedType)); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(value).descriptionAndTooltip(description).create(); - } + PsiClass psiClass = PsiUtil.resolveClassInType(type); + if (psiClass != null && psiClass.isEnum() + && !(expr instanceof PsiReferenceExpression refExpr && refExpr.resolve() instanceof PsiEnumConstant)) { + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(value) + .descriptionAndTooltip(JavaErrorBundle.message("annotation.non.enum.constant.attribute.value")) + .create(); + } - if (value instanceof PsiExpression) { - PsiExpression expr = (PsiExpression) value; - PsiType type = expr.getType(); + if (type != null && TypeConversionUtil.areTypesAssignmentCompatible(expectedType, expr) + || expectedType instanceof PsiArrayType expectedArrayType + && TypeConversionUtil.areTypesAssignmentCompatible(expectedArrayType.getComponentType(), expr)) { + return null; + } - final PsiClass psiClass = PsiUtil.resolveClassInType(type); - if (psiClass != null && psiClass.isEnum() && !(expr instanceof PsiReferenceExpression && ((PsiReferenceExpression) expr).resolve() instanceof PsiEnumConstant)) { - String description = JavaErrorBundle.message("annotation.non.enum.constant.attribute.value"); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(value).descriptionAndTooltip(description).create(); - } + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(value) + .descriptionAndTooltip(JavaErrorLocalize.incompatibleTypes( + JavaHighlightUtil.formatType(expectedType), + JavaHighlightUtil.formatType(type) + )) + .registerFix(QuickFixFactory.getInstance().createSurroundWithQuotesAnnotationParameterValueFix(value, expectedType)) + .create(); + } - if (type != null && TypeConversionUtil.areTypesAssignmentCompatible(expectedType, expr) || expectedType instanceof PsiArrayType && TypeConversionUtil.areTypesAssignmentCompatible(( - (PsiArrayType) expectedType).getComponentType(), expr)) { + LOG.error("Unknown annotation member value: " + value); return null; - } - - String description = JavaErrorBundle.message("incompatible.types", JavaHighlightUtil.formatType(expectedType), JavaHighlightUtil.formatType(type)); - HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(value).descriptionAndTooltip(description).create(); - QuickFixAction.registerQuickFixAction(info, QuickFixFactory.getInstance().createSurroundWithQuotesAnnotationParameterValueFix(value, expectedType)); - return info; } - LOG.error("Unknown annotation member value: " + value); - return null; - } + @RequiredReadAction + public static HighlightInfo checkDuplicateAnnotations(@Nonnull PsiAnnotation annotationToCheck, @Nonnull LanguageLevel languageLevel) { + PsiAnnotationOwner owner = annotationToCheck.getOwner(); + if (owner == null) { + return null; + } - public static HighlightInfo checkDuplicateAnnotations(@Nonnull PsiAnnotation annotationToCheck, @Nonnull LanguageLevel languageLevel) { - PsiAnnotationOwner owner = annotationToCheck.getOwner(); - if (owner == null) { - return null; - } + PsiJavaCodeReferenceElement element = annotationToCheck.getNameReferenceElement(); + if (element == null || !(element.resolve() instanceof PsiClass annotationType)) { + return null; + } - PsiJavaCodeReferenceElement element = annotationToCheck.getNameReferenceElement(); - if (element == null) { - return null; - } - PsiElement resolved = element.resolve(); - if (!(resolved instanceof PsiClass)) { - return null; - } + PsiClass contained = contained(annotationType); + String containedElementFQN = contained == null ? null : contained.getQualifiedName(); - PsiClass annotationType = (PsiClass) resolved; - - PsiClass contained = contained(annotationType); - String containedElementFQN = contained == null ? null : contained.getQualifiedName(); - - if (containedElementFQN != null) { - String containerName = annotationType.getQualifiedName(); - if (isAnnotationRepeatedTwice(owner, containedElementFQN)) { - String description = JavaErrorBundle.message("annotation.container.wrong.place", containerName); - return annotationError(annotationToCheck, description); - } - } else if (isAnnotationRepeatedTwice(owner, annotationType.getQualifiedName())) { - if (!languageLevel.isAtLeast(LanguageLevel.JDK_1_8)) { - String description = JavaErrorBundle.message("annotation.duplicate.annotation"); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(element).descriptionAndTooltip(description).create(); - } - - PsiAnnotation metaAnno = PsiImplUtil.findAnnotation(annotationType.getModifierList(), JavaClassNames.JAVA_LANG_ANNOTATION_REPEATABLE); - if (metaAnno == null) { - String explanation = JavaErrorBundle.message("annotation.non.repeatable", annotationType.getQualifiedName()); - String description = JavaErrorBundle.message("annotation.duplicate.explained", explanation); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(element).descriptionAndTooltip(description).create(); - } - - String explanation = doCheckRepeatableAnnotation(metaAnno); - if (explanation != null) { - String description = JavaErrorBundle.message("annotation.duplicate.explained", explanation); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(element).descriptionAndTooltip(description).create(); - } - - PsiClass container = getRepeatableContainer(metaAnno); - if (container != null) { - PsiAnnotation.TargetType[] targets = AnnotationTargetUtil.getTargetsForLocation(owner); - PsiAnnotation.TargetType applicable = AnnotationTargetUtil.findAnnotationTarget(container, targets); - if (applicable == null) { - String target = JavaErrorBundle.message("annotation.target." + targets[0]); - String message = JavaErrorBundle.message("annotation.container.not.applicable", container.getName(), target); - return annotationError(annotationToCheck, message); + if (containedElementFQN != null) { + String containerName = annotationType.getQualifiedName(); + if (isAnnotationRepeatedTwice(owner, containedElementFQN)) { + return annotationError(annotationToCheck, JavaErrorLocalize.annotationContainerWrongPlace(containerName)); + } } - } - } + else if (isAnnotationRepeatedTwice(owner, annotationType.getQualifiedName())) { + if (!languageLevel.isAtLeast(LanguageLevel.JDK_1_8)) { + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(element) + .descriptionAndTooltip(JavaErrorLocalize.annotationDuplicateAnnotation()) + .create(); + } - return null; - } + PsiAnnotation metaAnno = + PsiImplUtil.findAnnotation(annotationType.getModifierList(), JavaClassNames.JAVA_LANG_ANNOTATION_REPEATABLE); + if (metaAnno == null) { + LocalizeValue explanation = JavaErrorLocalize.annotationNonRepeatable(annotationType.getQualifiedName()); + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(element) + .descriptionAndTooltip(JavaErrorLocalize.annotationDuplicateExplained(explanation)) + .create(); + } - // returns contained element - private static PsiClass contained(PsiClass annotationType) { - if (!annotationType.isAnnotationType()) { - return null; - } - PsiMethod[] values = annotationType.findMethodsByName("value", false); - if (values.length != 1) { - return null; - } - PsiMethod value = values[0]; - PsiType returnType = value.getReturnType(); - if (!(returnType instanceof PsiArrayType)) { - return null; - } - PsiType type = ((PsiArrayType) returnType).getComponentType(); - if (!(type instanceof PsiClassType)) { - return null; - } - PsiClass contained = ((PsiClassType) type).resolve(); - if (contained == null || !contained.isAnnotationType()) { - return null; - } - if (PsiImplUtil.findAnnotation(contained.getModifierList(), JavaClassNames.JAVA_LANG_ANNOTATION_REPEATABLE) == null) { - return null; - } + String explanation = doCheckRepeatableAnnotation(metaAnno); + if (explanation != null) { + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(element) + .descriptionAndTooltip(JavaErrorLocalize.annotationDuplicateExplained(explanation)) + .create(); + } - return contained; - } - - private static boolean isAnnotationRepeatedTwice(@Nonnull PsiAnnotationOwner owner, @Nullable String qualifiedName) { - int count = 0; - for (PsiAnnotation annotation : owner.getAnnotations()) { - PsiJavaCodeReferenceElement nameRef = annotation.getNameReferenceElement(); - if (nameRef == null) { - continue; - } - PsiElement resolved = nameRef.resolve(); - if (!(resolved instanceof PsiClass) || !Comparing.equal(qualifiedName, ((PsiClass) resolved).getQualifiedName())) { - continue; - } - if (++count == 2) { - return true; - } - } - return false; - } - - @Nullable - public static HighlightInfo checkMissingAttributes(PsiAnnotation annotation) { - PsiJavaCodeReferenceElement nameRef = annotation.getNameReferenceElement(); - if (nameRef == null) { - return null; - } - PsiClass aClass = (PsiClass) nameRef.resolve(); - if (aClass != null && aClass.isAnnotationType()) { - Set names = new HashSet<>(); - PsiNameValuePair[] attributes = annotation.getParameterList().getAttributes(); - for (PsiNameValuePair attribute : attributes) { - final String name = attribute.getName(); - if (name != null) { - names.add(name); - } else { - names.add(PsiAnnotation.DEFAULT_REFERENCED_METHOD_NAME); - } - } - - PsiMethod[] annotationMethods = aClass.getMethods(); - List missed = new ArrayList<>(); - for (PsiMethod method : annotationMethods) { - if (PsiUtil.isAnnotationMethod(method)) { - PsiAnnotationMethod annotationMethod = (PsiAnnotationMethod) method; - if (annotationMethod.getDefaultValue() == null) { - if (!names.contains(annotationMethod.getName())) { - missed.add(annotationMethod.getName()); - } - } - } - } - - if (!missed.isEmpty()) { - StringBuffer buff = new StringBuffer("'" + missed.get(0) + "'"); - for (int i = 1; i < missed.size(); i++) { - buff.append(", "); - buff.append("'").append(missed.get(i)).append("'"); - } - - String description = JavaErrorBundle.message("annotation.missing.attribute", buff); - HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(nameRef).descriptionAndTooltip(description).create(); - IntentionAction fix = QuickFixFactory.getInstance().createAddMissingRequiredAnnotationParametersFix(annotation, annotationMethods, missed); - QuickFixAction.registerQuickFixAction(info, fix); - return info; - } - } + PsiClass container = getRepeatableContainer(metaAnno); + if (container != null) { + PsiAnnotation.TargetType[] targets = AnnotationTargetUtil.getTargetsForLocation(owner); + PsiAnnotation.TargetType applicable = AnnotationTargetUtil.findAnnotationTarget(container, targets); + if (applicable == null) { + String target = JavaErrorBundle.message("annotation.target." + targets[0]); + return annotationError( + annotationToCheck, + JavaErrorLocalize.annotationContainerNotApplicable(container.getName(), target) + ); + } + } + } - return null; - } - - @Nullable - public static HighlightInfo checkConstantExpression(PsiExpression expression) { - final PsiElement parent = expression.getParent(); - if (PsiUtil.isAnnotationMethod(parent) || parent instanceof PsiNameValuePair || parent instanceof PsiArrayInitializerMemberValue) { - if (!PsiUtil.isConstantExpression(expression)) { - String description = JavaErrorBundle.message("annotation.non.constant.attribute.value"); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(expression).descriptionAndTooltip(description).create(); - } + return null; } - return null; - } + // returns contained element + private static PsiClass contained(PsiClass annotationType) { + if (!annotationType.isAnnotationType()) { + return null; + } + PsiMethod[] values = annotationType.findMethodsByName("value", false); + if (values.length != 1) { + return null; + } + PsiMethod value = values[0]; + PsiType returnType = value.getReturnType(); + if (!(returnType instanceof PsiArrayType arrayType)) { + return null; + } + if (!(arrayType.getComponentType() instanceof PsiClassType componentClassType)) { + return null; + } + PsiClass contained = componentClassType.resolve(); + if (contained == null || !contained.isAnnotationType()) { + return null; + } + if (PsiImplUtil.findAnnotation(contained.getModifierList(), JavaClassNames.JAVA_LANG_ANNOTATION_REPEATABLE) == null) { + return null; + } - @Nullable - public static HighlightInfo checkValidAnnotationType(PsiType type, final PsiTypeElement typeElement) { - if (type != null && type.accept(AnnotationReturnTypeVisitor.INSTANCE).booleanValue()) { - return null; - } - String description = JavaErrorBundle.message("annotation.invalid.annotation.member.type", type != null ? type.getPresentableText() : null); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(typeElement).descriptionAndTooltip(description).create(); - } - - private static final ElementPattern ANY_ANNOTATION_ALLOWED = psiElement().andOr(psiElement().withParent(PsiNameValuePair.class), psiElement().withParents - (PsiArrayInitializerMemberValue.class, PsiNameValuePair.class), psiElement().withParents(PsiArrayInitializerMemberValue.class, PsiAnnotationMethod.class), psiElement().withParent - (PsiAnnotationMethod.class).afterLeaf(PsiKeyword.DEFAULT)); - - @Nullable - public static HighlightInfo checkApplicability(@Nonnull PsiAnnotation annotation, @Nonnull LanguageLevel level, @Nonnull PsiFile file) { - if (ANY_ANNOTATION_ALLOWED.accepts(annotation)) { - return null; + return contained; } - PsiJavaCodeReferenceElement nameRef = annotation.getNameReferenceElement(); - if (nameRef == null) { - return null; + @RequiredReadAction + private static boolean isAnnotationRepeatedTwice(@Nonnull PsiAnnotationOwner owner, @Nullable String qualifiedName) { + int count = 0; + for (PsiAnnotation annotation : owner.getAnnotations()) { + PsiJavaCodeReferenceElement nameRef = annotation.getNameReferenceElement(); + if (nameRef == null + || !(nameRef.resolve() instanceof PsiClass psiClass) + || !Comparing.equal(qualifiedName, psiClass.getQualifiedName())) { + continue; + } + if (++count == 2) { + return true; + } + } + return false; } - PsiAnnotationOwner owner = annotation.getOwner(); - PsiAnnotation.TargetType[] targets = AnnotationTargetUtil.getTargetsForLocation(owner); - if (owner == null || targets.length == 0) { - String message = JavaErrorBundle.message("annotation.not.allowed.here"); - return annotationError(annotation, message); - } + @Nullable + @RequiredReadAction + public static HighlightInfo checkMissingAttributes(PsiAnnotation annotation) { + PsiJavaCodeReferenceElement nameRef = annotation.getNameReferenceElement(); + if (nameRef == null) { + return null; + } + PsiClass aClass = (PsiClass)nameRef.resolve(); + if (aClass != null && aClass.isAnnotationType()) { + Set names = new HashSet<>(); + PsiNameValuePair[] attributes = annotation.getParameterList().getAttributes(); + for (PsiNameValuePair attribute : attributes) { + String name = attribute.getName(); + if (name != null) { + names.add(name); + } + else { + names.add(PsiAnnotation.DEFAULT_REFERENCED_METHOD_NAME); + } + } - if (!(owner instanceof PsiModifierList)) { - HighlightInfo info = HighlightUtil.checkFeature(annotation, JavaFeature.TYPE_ANNOTATIONS, level, file); - if (info != null) { - return info; - } - } + PsiMethod[] annotationMethods = aClass.getMethods(); + List missed = new ArrayList<>(); + for (PsiMethod method : annotationMethods) { + if (PsiUtil.isAnnotationMethod(method)) { + PsiAnnotationMethod annotationMethod = (PsiAnnotationMethod)method; + if (annotationMethod.getDefaultValue() == null && !names.contains(annotationMethod.getName())) { + missed.add(annotationMethod.getName()); + } + } + } + + if (!missed.isEmpty()) { + StringBuffer buff = new StringBuffer("'" + missed.get(0) + "'"); + for (int i = 1; i < missed.size(); i++) { + buff.append(", "); + buff.append("'").append(missed.get(i)).append("'"); + } + + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(nameRef) + .descriptionAndTooltip(JavaErrorLocalize.annotationMissingAttribute(buff)) + .registerFix( + QuickFixFactory.getInstance().createAddMissingRequiredAnnotationParametersFix(annotation, annotationMethods, missed) + ) + .create(); + } + } - PsiAnnotation.TargetType applicable = AnnotationTargetUtil.findAnnotationTarget(annotation, targets); - if (applicable == PsiAnnotation.TargetType.UNKNOWN) { - return null; + return null; } - if (applicable == null) { - String target = JavaErrorBundle.message("annotation.target." + targets[0]); - String message = JavaErrorBundle.message("annotation.not.applicable", nameRef.getText(), target); - return annotationError(annotation, message); + @Nullable + @RequiredReadAction + public static HighlightInfo checkConstantExpression(PsiExpression expression) { + PsiElement parent = expression.getParent(); + if (PsiUtil.isAnnotationMethod(parent) || parent instanceof PsiNameValuePair || parent instanceof PsiArrayInitializerMemberValue) { + if (!PsiUtil.isConstantExpression(expression)) { + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(expression) + .descriptionAndTooltip(JavaErrorLocalize.annotationNonConstantAttributeValue()) + .create(); + } + } + + return null; } - if (applicable == PsiAnnotation.TargetType.TYPE_USE) { - if (owner instanceof PsiClassReferenceType) { - PsiJavaCodeReferenceElement ref = ((PsiClassReferenceType) owner).getReference(); - HighlightInfo info = checkReferenceTarget(annotation, ref); - if (info != null) { - return info; - } - } else if (owner instanceof PsiModifierList) { - PsiElement nextElement = PsiTreeUtil.skipSiblingsForward((PsiModifierList) owner, PsiComment.class, PsiWhiteSpace.class, PsiTypeParameterList.class); - if (nextElement instanceof PsiTypeElement) { - PsiTypeElement typeElement = (PsiTypeElement) nextElement; - PsiType type = typeElement.getType(); - if (PsiType.VOID.equals(type)) { - String message = JavaErrorBundle.message("annotation.not.allowed.void"); - return annotationError(annotation, message); - } - if (!(type instanceof PsiPrimitiveType)) { - PsiJavaCodeReferenceElement ref = getOutermostReferenceElement(typeElement.getInnermostComponentReferenceElement()); - HighlightInfo info = checkReferenceTarget(annotation, ref); + @Nullable + @RequiredReadAction + public static HighlightInfo checkValidAnnotationType(PsiType type, PsiTypeElement typeElement) { + if (type != null && type.accept(AnnotationReturnTypeVisitor.INSTANCE)) { + return null; + } + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(typeElement) + .descriptionAndTooltip(JavaErrorLocalize.annotationInvalidAnnotationMemberType(type != null ? type.getPresentableText() : "?")) + .create(); + } + + private static final ElementPattern ANY_ANNOTATION_ALLOWED = psiElement().andOr( + psiElement().withParent(PsiNameValuePair.class), + psiElement().withParents(PsiArrayInitializerMemberValue.class, PsiNameValuePair.class), + psiElement().withParents(PsiArrayInitializerMemberValue.class, PsiAnnotationMethod.class), + psiElement().withParent(PsiAnnotationMethod.class).afterLeaf(PsiKeyword.DEFAULT) + ); + + @Nullable + @RequiredReadAction + public static HighlightInfo checkApplicability(@Nonnull PsiAnnotation annotation, @Nonnull LanguageLevel level, @Nonnull PsiFile file) { + if (ANY_ANNOTATION_ALLOWED.accepts(annotation)) { + return null; + } + + PsiJavaCodeReferenceElement nameRef = annotation.getNameReferenceElement(); + if (nameRef == null) { + return null; + } + + PsiAnnotationOwner owner = annotation.getOwner(); + PsiAnnotation.TargetType[] targets = AnnotationTargetUtil.getTargetsForLocation(owner); + if (owner == null || targets.length == 0) { + return annotationError(annotation, JavaErrorLocalize.annotationNotAllowedHere()); + } + + if (!(owner instanceof PsiModifierList)) { + HighlightInfo info = HighlightUtil.checkFeature(annotation, JavaFeature.TYPE_ANNOTATIONS, level, file); if (info != null) { - return info; + return info; } - } } - } else if (owner instanceof PsiTypeElement) { - PsiElement context = PsiTreeUtil.skipParentsOfType((PsiTypeElement) owner, PsiTypeElement.class); - if (context instanceof PsiClassObjectAccessExpression) { - String message = JavaErrorBundle.message("annotation.not.allowed.class"); - return annotationError(annotation, message); + + PsiAnnotation.TargetType applicable = AnnotationTargetUtil.findAnnotationTarget(annotation, targets); + if (applicable == PsiAnnotation.TargetType.UNKNOWN) { + return null; } - } - } - return null; - } + if (applicable == null) { + String target = JavaErrorBundle.message("annotation.target." + targets[0]); + return annotationError(annotation, JavaErrorLocalize.annotationNotApplicable(nameRef.getText(), target)); + } - private static HighlightInfo annotationError(PsiAnnotation annotation, String message) { - HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(annotation).descriptionAndTooltip(message).create(); - QuickFixAction.registerQuickFixAction(info, new DeleteAnnotationAction(annotation)); - return info; - } + if (applicable == PsiAnnotation.TargetType.TYPE_USE) { + if (owner instanceof PsiClassReferenceType classRefType) { + PsiJavaCodeReferenceElement ref = classRefType.getReference(); + HighlightInfo info = checkReferenceTarget(annotation, ref); + if (info != null) { + return info; + } + } + else if (owner instanceof PsiModifierList modifierList) { + PsiElement nextElement = + PsiTreeUtil.skipSiblingsForward(modifierList, PsiComment.class, PsiWhiteSpace.class, PsiTypeParameterList.class); + if (nextElement instanceof PsiTypeElement) { + PsiTypeElement typeElement = (PsiTypeElement)nextElement; + PsiType type = typeElement.getType(); + if (PsiType.VOID.equals(type)) { + return annotationError(annotation, JavaErrorLocalize.annotationNotAllowedVoid()); + } + if (!(type instanceof PsiPrimitiveType)) { + PsiJavaCodeReferenceElement ref = getOutermostReferenceElement(typeElement.getInnermostComponentReferenceElement()); + HighlightInfo info = checkReferenceTarget(annotation, ref); + if (info != null) { + return info; + } + } + } + } + else if (owner instanceof PsiTypeElement) { + PsiElement context = PsiTreeUtil.skipParentsOfType((PsiTypeElement)owner, PsiTypeElement.class); + if (context instanceof PsiClassObjectAccessExpression) { + return annotationError(annotation, JavaErrorLocalize.annotationNotAllowedClass()); + } + } + } - @Nullable - private static HighlightInfo checkReferenceTarget(PsiAnnotation annotation, @Nullable PsiJavaCodeReferenceElement ref) { - if (ref == null) { - return null; - } - PsiElement refTarget = ref.resolve(); - if (refTarget == null) { - return null; + return null; } - String message = null; - if (!(refTarget instanceof PsiClass)) { - message = JavaErrorBundle.message("annotation.not.allowed.ref"); - } else { - PsiElement parent = ref.getParent(); - if (parent instanceof PsiJavaCodeReferenceElement) { - PsiElement qualified = ((PsiJavaCodeReferenceElement) parent).resolve(); - if (qualified instanceof PsiMember && ((PsiMember) qualified).hasModifierProperty(PsiModifier.STATIC)) { - message = JavaErrorBundle.message("annotation.not.allowed.static"); - } - } + @RequiredReadAction + private static HighlightInfo annotationError(PsiAnnotation annotation, LocalizeValue message) { + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(annotation) + .descriptionAndTooltip(message) + .registerFix(new DeleteAnnotationAction(annotation)) + .create(); } - return message != null ? annotationError(annotation, message) : null; - } + @Nullable + @RequiredReadAction + private static HighlightInfo checkReferenceTarget(PsiAnnotation annotation, @Nullable PsiJavaCodeReferenceElement ref) { + if (ref == null) { + return null; + } + PsiElement refTarget = ref.resolve(); + if (refTarget == null) { + return null; + } - @Nullable - private static PsiJavaCodeReferenceElement getOutermostReferenceElement(@Nullable PsiJavaCodeReferenceElement ref) { - if (ref == null) { - return null; + if (!(refTarget instanceof PsiClass)) { + return annotationError(annotation, JavaErrorLocalize.annotationNotAllowedRef()); + } + else if (ref.getParent() instanceof PsiJavaCodeReferenceElement javaCodeRef + && javaCodeRef.resolve() instanceof PsiMember member && member.isStatic()) { + return annotationError(annotation, JavaErrorLocalize.annotationNotAllowedStatic()); + } + return null; } - PsiElement qualifier; - while ((qualifier = ref.getQualifier()) instanceof PsiJavaCodeReferenceElement) { - ref = (PsiJavaCodeReferenceElement) qualifier; - } - return ref; - } - - @Nullable - public static HighlightInfo checkAnnotationType(PsiAnnotation annotation) { - PsiJavaCodeReferenceElement nameReferenceElement = annotation.getNameReferenceElement(); - if (nameReferenceElement != null) { - PsiElement resolved = nameReferenceElement.resolve(); - if (!(resolved instanceof PsiClass) || !((PsiClass) resolved).isAnnotationType()) { - String description = JavaErrorBundle.message("annotation.annotation.type.expected"); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(nameReferenceElement).descriptionAndTooltip(description).create(); - } - } - return null; - } - - @Nullable - public static HighlightInfo checkCyclicMemberType(PsiTypeElement typeElement, PsiClass aClass) { - LOG.assertTrue(aClass.isAnnotationType()); - PsiType type = typeElement.getType(); - final Set checked = new HashSet<>(); - if (cyclicDependencies(aClass, type, checked, aClass.getManager())) { - String description = JavaErrorBundle.message("annotation.cyclic.element.type"); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(typeElement).descriptionAndTooltip(description).create(); - } - return null; - } - - private static boolean cyclicDependencies(PsiClass aClass, PsiType type, @Nonnull Set checked, @Nonnull PsiManager manager) { - final PsiClass resolvedClass = PsiUtil.resolveClassInType(type); - if (resolvedClass != null && resolvedClass.isAnnotationType()) { - if (aClass == resolvedClass) { - return true; - } - if (!checked.add(resolvedClass) || !manager.isInProject(resolvedClass)) { - return false; - } - final PsiMethod[] methods = resolvedClass.getMethods(); - for (PsiMethod method : methods) { - if (cyclicDependencies(aClass, method.getReturnType(), checked, manager)) { - return true; + @Nullable + private static PsiJavaCodeReferenceElement getOutermostReferenceElement(@Nullable PsiJavaCodeReferenceElement ref) { + if (ref == null) { + return null; } - } - } - return false; - } - - public static HighlightInfo checkClashesWithSuperMethods(@Nonnull PsiAnnotationMethod psiMethod) { - final PsiIdentifier nameIdentifier = psiMethod.getNameIdentifier(); - if (nameIdentifier != null) { - final PsiMethod[] methods = psiMethod.findDeepestSuperMethods(); - for (PsiMethod method : methods) { - final PsiClass containingClass = method.getContainingClass(); - if (containingClass != null) { - final String qualifiedName = containingClass.getQualifiedName(); - if (JavaClassNames.JAVA_LANG_OBJECT.equals(qualifiedName) || JavaClassNames.JAVA_LANG_ANNOTATION_ANNOTATION.equals(qualifiedName)) { - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(nameIdentifier).descriptionAndTooltip("@interface member clashes with '" + JavaHighlightUtil.formatMethod - (method) + "' in " + HighlightUtil.formatClass(containingClass)).create(); - } - } - } - } - return null; - } - - @Nullable - public static HighlightInfo checkAnnotationDeclaration(final PsiElement parent, final PsiReferenceList list) { - if (PsiUtil.isAnnotationMethod(parent)) { - PsiAnnotationMethod method = (PsiAnnotationMethod) parent; - if (list == method.getThrowsList()) { - String description = JavaErrorBundle.message("annotation.members.may.not.have.throws.list"); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(list).descriptionAndTooltip(description).create(); - } - } else if (parent instanceof PsiClass && ((PsiClass) parent).isAnnotationType()) { - if (PsiKeyword.EXTENDS.equals(list.getFirstChild().getText())) { - String description = JavaErrorBundle.message("annotation.may.not.have.extends.list"); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(list).descriptionAndTooltip(description).create(); - } - } - return null; - } - - @Nullable - public static HighlightInfo checkPackageAnnotationContainingFile(PsiPackageStatement statement, PsiFile file) { - PsiModifierList annotationList = statement.getAnnotationList(); - if (annotationList != null && !PsiJavaPackage.PACKAGE_INFO_FILE.equals(file.getName())) { - String message = JavaErrorBundle.message("invalid.package.annotation.containing.file"); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(annotationList.getTextRange()).descriptionAndTooltip(message).create(); - } - return null; - } - - @Nullable - public static HighlightInfo checkTargetAnnotationDuplicates(PsiAnnotation annotation) { - PsiJavaCodeReferenceElement nameRef = annotation.getNameReferenceElement(); - if (nameRef == null) { - return null; - } - PsiElement resolved = nameRef.resolve(); - if (!(resolved instanceof PsiClass) || !JavaClassNames.JAVA_LANG_ANNOTATION_TARGET.equals(((PsiClass) resolved).getQualifiedName())) { - return null; + PsiElement qualifier; + while ((qualifier = ref.getQualifier()) instanceof PsiJavaCodeReferenceElement) { + ref = (PsiJavaCodeReferenceElement)qualifier; + } + return ref; + } + + @Nullable + @RequiredReadAction + public static HighlightInfo checkAnnotationType(PsiAnnotation annotation) { + PsiJavaCodeReferenceElement nameRefElem = annotation.getNameReferenceElement(); + if (nameRefElem != null && (!(nameRefElem.resolve() instanceof PsiClass annotationClass) || !annotationClass.isAnnotationType())) { + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(nameRefElem) + .descriptionAndTooltip(JavaErrorLocalize.annotationAnnotationTypeExpected()) + .create(); + } + return null; } - PsiNameValuePair[] attributes = annotation.getParameterList().getAttributes(); - if (attributes.length < 1) { - return null; - } - PsiAnnotationMemberValue value = attributes[0].getValue(); - if (!(value instanceof PsiArrayInitializerMemberValue)) { - return null; + @Nullable + @RequiredReadAction + public static HighlightInfo checkCyclicMemberType(PsiTypeElement typeElement, PsiClass aClass) { + LOG.assertTrue(aClass.isAnnotationType()); + PsiType type = typeElement.getType(); + Set checked = new HashSet<>(); + if (cyclicDependencies(aClass, type, checked, aClass.getManager())) { + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(typeElement) + .descriptionAndTooltip(JavaErrorLocalize.annotationCyclicElementType()) + .create(); + } + return null; } - PsiAnnotationMemberValue[] arrayInitializers = ((PsiArrayInitializerMemberValue) value).getInitializers(); - Set targets = new HashSet<>(); - for (PsiAnnotationMemberValue initializer : arrayInitializers) { - if (initializer instanceof PsiReferenceExpression) { - PsiElement target = ((PsiReferenceExpression) initializer).resolve(); - if (target != null) { - if (targets.contains(target)) { - String description = JavaErrorBundle.message("repeated.annotation.target"); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(initializer).descriptionAndTooltip(description).create(); - } - targets.add(target); - } - } + + private static boolean cyclicDependencies(PsiClass aClass, PsiType type, @Nonnull Set checked, @Nonnull PsiManager manager) { + PsiClass resolvedClass = PsiUtil.resolveClassInType(type); + if (resolvedClass != null && resolvedClass.isAnnotationType()) { + if (aClass == resolvedClass) { + return true; + } + if (!checked.add(resolvedClass) || !manager.isInProject(resolvedClass)) { + return false; + } + PsiMethod[] methods = resolvedClass.getMethods(); + for (PsiMethod method : methods) { + if (cyclicDependencies(aClass, method.getReturnType(), checked, manager)) { + return true; + } + } + } + return false; } - return null; - } - - @Nullable - public static HighlightInfo checkFunctionalInterface(@Nonnull PsiAnnotation annotation, @Nonnull LanguageLevel languageLevel) { - if (languageLevel.isAtLeast(LanguageLevel.JDK_1_8) && Comparing.strEqual(annotation.getQualifiedName(), JavaClassNames.JAVA_LANG_FUNCTIONAL_INTERFACE)) { - final PsiAnnotationOwner owner = annotation.getOwner(); - if (owner instanceof PsiModifierList) { - final PsiElement parent = ((PsiModifierList) owner).getParent(); - if (parent instanceof PsiClass) { - final String errorMessage = LambdaHighlightingUtil.checkInterfaceFunctional((PsiClass) parent, ((PsiClass) parent).getName() + " is not a functional interface"); - if (errorMessage != null) { - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(annotation).descriptionAndTooltip(errorMessage).create(); - } - } - } + + @RequiredReadAction + public static HighlightInfo checkClashesWithSuperMethods(@Nonnull PsiAnnotationMethod psiMethod) { + PsiIdentifier nameIdentifier = psiMethod.getNameIdentifier(); + if (nameIdentifier != null) { + PsiMethod[] methods = psiMethod.findDeepestSuperMethods(); + for (PsiMethod method : methods) { + PsiClass containingClass = method.getContainingClass(); + if (containingClass != null) { + String qualifiedName = containingClass.getQualifiedName(); + if (JavaClassNames.JAVA_LANG_OBJECT.equals(qualifiedName) + || JavaClassNames.JAVA_LANG_ANNOTATION_ANNOTATION.equals(qualifiedName)) { + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(nameIdentifier) + .descriptionAndTooltip( + "@interface member clashes with '" + JavaHighlightUtil.formatMethod(method) + + "' in " + HighlightUtil.formatClass(containingClass) + ) + .create(); + } + } + } + } + return null; } - return null; - } - - @Nullable - public static HighlightInfo checkRepeatableAnnotation(PsiAnnotation annotation) { - String qualifiedName = annotation.getQualifiedName(); - if (!JavaClassNames.JAVA_LANG_ANNOTATION_REPEATABLE.equals(qualifiedName)) { - return null; + + @Nullable + @RequiredReadAction + public static HighlightInfo checkAnnotationDeclaration(PsiElement parent, PsiReferenceList list) { + if (PsiUtil.isAnnotationMethod(parent)) { + PsiAnnotationMethod method = (PsiAnnotationMethod)parent; + if (list == method.getThrowsList()) { + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(list) + .descriptionAndTooltip(JavaErrorLocalize.annotationMembersMayNotHaveThrowsList()) + .create(); + } + } + else if (parent instanceof PsiClass annotationClass && annotationClass.isAnnotationType()) { + if (PsiKeyword.EXTENDS.equals(list.getFirstChild().getText())) { + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(list) + .descriptionAndTooltip(JavaErrorLocalize.annotationMayNotHaveExtendsList()) + .create(); + } + } + return null; } - String description = doCheckRepeatableAnnotation(annotation); - if (description != null) { - PsiAnnotationMemberValue containerRef = PsiImplUtil.findAttributeValue(annotation, null); - if (containerRef != null) { - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(containerRef).descriptionAndTooltip(description).create(); - } + @Nullable + @RequiredReadAction + public static HighlightInfo checkPackageAnnotationContainingFile(PsiPackageStatement statement, PsiFile file) { + PsiModifierList annotationList = statement.getAnnotationList(); + if (annotationList != null && !PsiJavaPackage.PACKAGE_INFO_FILE.equals(file.getName())) { + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(annotationList.getTextRange()) + .descriptionAndTooltip(JavaErrorLocalize.invalidPackageAnnotationContainingFile()) + .create(); + } + return null; } - return null; - } + @Nullable + @RequiredReadAction + public static HighlightInfo checkTargetAnnotationDuplicates(PsiAnnotation annotation) { + PsiJavaCodeReferenceElement nameRef = annotation.getNameReferenceElement(); + if (nameRef == null) { + return null; + } - @Nullable - private static String doCheckRepeatableAnnotation(@Nonnull PsiAnnotation annotation) { - PsiAnnotationOwner owner = annotation.getOwner(); - if (!(owner instanceof PsiModifierList)) { - return null; - } - PsiElement target = ((PsiModifierList) owner).getParent(); - if (!(target instanceof PsiClass) || !((PsiClass) target).isAnnotationType()) { - return null; - } - PsiClass container = getRepeatableContainer(annotation); - if (container == null) { - return null; - } + if (!(nameRef.resolve() instanceof PsiClass annotationClass) + || !JavaClassNames.JAVA_LANG_ANNOTATION_TARGET.equals(annotationClass.getQualifiedName())) { + return null; + } - PsiMethod[] methods = container.findMethodsByName("value", false); - if (methods.length == 0) { - return JavaErrorBundle.message("annotation.container.no.value", container.getQualifiedName()); + PsiNameValuePair[] attributes = annotation.getParameterList().getAttributes(); + if (attributes.length < 1) { + return null; + } + PsiAnnotationMemberValue value = attributes[0].getValue(); + if (!(value instanceof PsiArrayInitializerMemberValue arrayInitializerMemberValue)) { + return null; + } + PsiAnnotationMemberValue[] arrayInitializers = arrayInitializerMemberValue.getInitializers(); + Set targets = new HashSet<>(); + for (PsiAnnotationMemberValue initializer : arrayInitializers) { + if (initializer instanceof PsiReferenceExpression refExpr) { + PsiElement target = refExpr.resolve(); + if (target != null) { + if (targets.contains(target)) { + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(initializer) + .descriptionAndTooltip(JavaErrorLocalize.repeatedAnnotationTarget()) + .create(); + } + targets.add(target); + } + } + } + return null; } - if (methods.length == 1) { - PsiType expected = new PsiImmediateClassType((PsiClass) target, PsiSubstitutor.EMPTY).createArrayType(); - if (!expected.equals(methods[0].getReturnType())) { - return JavaErrorBundle.message("annotation.container.bad.type", container.getQualifiedName(), JavaHighlightUtil.formatType(expected)); - } + @Nullable + @RequiredReadAction + public static HighlightInfo checkFunctionalInterface(@Nonnull PsiAnnotation annotation, @Nonnull LanguageLevel languageLevel) { + if (languageLevel.isAtLeast(LanguageLevel.JDK_1_8) + && Comparing.strEqual(annotation.getQualifiedName(), JavaClassNames.JAVA_LANG_FUNCTIONAL_INTERFACE)) { + PsiAnnotationOwner owner = annotation.getOwner(); + if (owner instanceof PsiModifierList modifierList + && modifierList.getParent() instanceof PsiClass psiClass) { + String errorMessage = LambdaHighlightingUtil.checkInterfaceFunctional( + psiClass, + psiClass.getName() + " is not a functional interface" + ); + if (errorMessage != null) { + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(annotation) + .descriptionAndTooltip(errorMessage) + .create(); + } + } + } + return null; } - RetentionPolicy targetPolicy = getRetentionPolicy((PsiClass) target); - if (targetPolicy != null) { - RetentionPolicy containerPolicy = getRetentionPolicy(container); - if (containerPolicy != null && targetPolicy.compareTo(containerPolicy) > 0) { - return JavaErrorBundle.message("annotation.container.low.retention", container.getQualifiedName(), containerPolicy); - } - } + @Nullable + @RequiredReadAction + public static HighlightInfo checkRepeatableAnnotation(PsiAnnotation annotation) { + String qualifiedName = annotation.getQualifiedName(); + if (!JavaClassNames.JAVA_LANG_ANNOTATION_REPEATABLE.equals(qualifiedName)) { + return null; + } + + String description = doCheckRepeatableAnnotation(annotation); + if (description != null) { + PsiAnnotationMemberValue containerRef = PsiImplUtil.findAttributeValue(annotation, null); + if (containerRef != null) { + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(containerRef) + .descriptionAndTooltip(description) + .create(); + } + } - Set repeatableTargets = AnnotationTargetUtil.getAnnotationTargets((PsiClass) target); - if (repeatableTargets != null) { - Set containerTargets = AnnotationTargetUtil.getAnnotationTargets(container); - if (containerTargets != null && !repeatableTargets.containsAll(containerTargets)) { - return JavaErrorBundle.message("annotation.container.wide.target", container.getQualifiedName()); - } + return null; } - return null; - } + @Nullable + @RequiredReadAction + private static String doCheckRepeatableAnnotation(@Nonnull PsiAnnotation annotation) { + PsiAnnotationOwner owner = annotation.getOwner(); + if (!(owner instanceof PsiModifierList modifierList)) { + return null; + } + if (!(modifierList.getParent() instanceof PsiClass targetClass) || !targetClass.isAnnotationType()) { + return null; + } + PsiClass container = getRepeatableContainer(annotation); + if (container == null) { + return null; + } - @Nullable - private static PsiClass getRepeatableContainer(@Nonnull PsiAnnotation annotation) { - PsiAnnotationMemberValue containerRef = PsiImplUtil.findAttributeValue(annotation, null); - if (!(containerRef instanceof PsiClassObjectAccessExpression)) { - return null; - } - PsiType containerType = ((PsiClassObjectAccessExpression) containerRef).getOperand().getType(); - if (!(containerType instanceof PsiClassType)) { - return null; - } - PsiClass container = ((PsiClassType) containerType).resolve(); - if (container == null || !container.isAnnotationType()) { - return null; - } - return container; - } - - @Nullable - public static HighlightInfo checkReceiverPlacement(PsiReceiverParameter parameter) { - PsiElement owner = parameter.getParent().getParent(); - if (owner == null) { - return null; - } + PsiMethod[] methods = container.findMethodsByName("value", false); + if (methods.length == 0) { + return JavaErrorLocalize.annotationContainerNoValue(container.getQualifiedName()).get(); + } - if (!(owner instanceof PsiMethod)) { - String text = JavaErrorBundle.message("receiver.wrong.context"); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(parameter.getIdentifier()).descriptionAndTooltip(text).create(); - } + if (methods.length == 1) { + PsiType expected = new PsiImmediateClassType(targetClass, PsiSubstitutor.EMPTY).createArrayType(); + if (!expected.equals(methods[0].getReturnType())) { + return JavaErrorLocalize.annotationContainerBadType(container.getQualifiedName(), JavaHighlightUtil.formatType(expected)) + .get(); + } + } + + RetentionPolicy targetPolicy = getRetentionPolicy(targetClass); + if (targetPolicy != null) { + RetentionPolicy containerPolicy = getRetentionPolicy(container); + if (containerPolicy != null && targetPolicy.compareTo(containerPolicy) > 0) { + return JavaErrorLocalize.annotationContainerLowRetention(container.getQualifiedName(), containerPolicy).get(); + } + } - PsiMethod method = (PsiMethod) owner; - if (isStatic(method) || method.isConstructor() && isStatic(method.getContainingClass())) { - String text = JavaErrorBundle.message("receiver.static.context"); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(parameter.getIdentifier()).descriptionAndTooltip(text).create(); + Set repeatableTargets = AnnotationTargetUtil.getAnnotationTargets(targetClass); + if (repeatableTargets != null) { + Set containerTargets = AnnotationTargetUtil.getAnnotationTargets(container); + if (containerTargets != null && !repeatableTargets.containsAll(containerTargets)) { + return JavaErrorLocalize.annotationContainerWideTarget(container.getQualifiedName()).get(); + } + } + + return null; } - PsiElement leftNeighbour = PsiTreeUtil.skipSiblingsBackward(parameter, PsiWhiteSpace.class); - if (leftNeighbour != null && !PsiUtil.isJavaToken(leftNeighbour, JavaTokenType.LPARENTH)) { - String text = JavaErrorBundle.message("receiver.wrong.position"); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(parameter.getIdentifier()).descriptionAndTooltip(text).create(); + @Nullable + @RequiredReadAction + private static PsiClass getRepeatableContainer(@Nonnull PsiAnnotation annotation) { + if (!(PsiImplUtil.findAttributeValue(annotation, null) instanceof PsiClassObjectAccessExpression containerRef)) { + return null; + } + if (!(containerRef.getOperand().getType() instanceof PsiClassType containerType)) { + return null; + } + PsiClass container = containerType.resolve(); + return container != null && container.isAnnotationType() ? container : null; } - return null; - } + @Nullable + @RequiredReadAction + public static HighlightInfo checkReceiverPlacement(PsiReceiverParameter parameter) { + PsiElement owner = parameter.getParent().getParent(); + if (owner == null) { + return null; + } - @Nullable - public static HighlightInfo checkReceiverType(PsiReceiverParameter parameter) { - PsiElement owner = parameter.getParent().getParent(); - if (!(owner instanceof PsiMethod)) { - return null; - } + if (!(owner instanceof PsiMethod method)) { + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(parameter.getIdentifier()) + .descriptionAndTooltip(JavaErrorLocalize.receiverWrongContext()) + .create(); + } - PsiMethod method = (PsiMethod) owner; - PsiClass enclosingClass = method.getContainingClass(); - if (method.isConstructor() && enclosingClass != null) { - enclosingClass = enclosingClass.getContainingClass(); - } + if (isStatic(method) || method.isConstructor() && isStatic(method.getContainingClass())) { + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(parameter.getIdentifier()) + .descriptionAndTooltip(JavaErrorLocalize.receiverStaticContext()) + .create(); + } - if (enclosingClass != null && !enclosingClass.equals(PsiUtil.resolveClassInType(parameter.getType()))) { - PsiElement range = ObjectUtil.notNull(parameter.getTypeElement(), parameter); - String text = JavaErrorBundle.message("receiver.type.mismatch"); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(range).descriptionAndTooltip(text).create(); - } + PsiElement leftNeighbour = PsiTreeUtil.skipSiblingsBackward(parameter, PsiWhiteSpace.class); + if (leftNeighbour != null && !PsiUtil.isJavaToken(leftNeighbour, JavaTokenType.LPARENTH)) { + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(parameter.getIdentifier()) + .descriptionAndTooltip(JavaErrorLocalize.receiverWrongPosition()) + .create(); + } - PsiThisExpression identifier = parameter.getIdentifier(); - if (enclosingClass != null && !enclosingClass.equals(PsiUtil.resolveClassInType(identifier.getType()))) { - String text = JavaErrorBundle.message("receiver.name.mismatch"); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(identifier).descriptionAndTooltip(text).create(); + return null; } - return null; - } + @Nullable + @RequiredReadAction + public static HighlightInfo checkReceiverType(PsiReceiverParameter parameter) { + PsiElement owner = parameter.getParent().getParent(); + if (!(owner instanceof PsiMethod)) { + return null; + } - private static boolean isStatic(PsiModifierListOwner owner) { - if (owner == null) { - return false; - } - if (owner instanceof PsiClass && ClassUtil.isTopLevelClass((PsiClass) owner)) { - return true; - } - PsiModifierList modifierList = owner.getModifierList(); - return modifierList != null && modifierList.hasModifierProperty(PsiModifier.STATIC); - } - - @Nullable - public static RetentionPolicy getRetentionPolicy(@Nonnull PsiClass annotation) { - PsiModifierList modifierList = annotation.getModifierList(); - if (modifierList != null) { - PsiAnnotation retentionAnno = modifierList.findAnnotation(JavaClassNames.JAVA_LANG_ANNOTATION_RETENTION); - if (retentionAnno == null) { - return RetentionPolicy.CLASS; - } - - PsiAnnotationMemberValue policyRef = PsiImplUtil.findAttributeValue(retentionAnno, null); - if (policyRef instanceof PsiReference) { - PsiElement field = ((PsiReference) policyRef).resolve(); - if (field instanceof PsiEnumConstant) { - String name = ((PsiEnumConstant) field).getName(); - try { - //noinspection ConstantConditions - return Enum.valueOf(RetentionPolicy.class, name); - } catch (Exception e) { - LOG.warn("Unknown policy: " + name); - } - } - } - } + PsiMethod method = (PsiMethod)owner; + PsiClass enclosingClass = method.getContainingClass(); + if (method.isConstructor() && enclosingClass != null) { + enclosingClass = enclosingClass.getContainingClass(); + } - return null; - } + if (enclosingClass != null && !enclosingClass.equals(PsiUtil.resolveClassInType(parameter.getType()))) { + PsiElement range = ObjectUtil.notNull(parameter.getTypeElement(), parameter); + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(range) + .descriptionAndTooltip(JavaErrorLocalize.receiverTypeMismatch()) + .create(); + } - public static class AnnotationReturnTypeVisitor extends PsiTypeVisitor { - public static final AnnotationReturnTypeVisitor INSTANCE = new AnnotationReturnTypeVisitor(); + PsiThisExpression identifier = parameter.getIdentifier(); + if (enclosingClass != null && !enclosingClass.equals(PsiUtil.resolveClassInType(identifier.getType()))) { + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(identifier) + .descriptionAndTooltip(JavaErrorLocalize.receiverNameMismatch()) + .create(); + } - @Override - public Boolean visitType(PsiType type) { - return Boolean.FALSE; + return null; } - @Override - public Boolean visitPrimitiveType(PsiPrimitiveType primitiveType) { - return PsiType.VOID.equals(primitiveType) || PsiType.NULL.equals(primitiveType) ? Boolean.FALSE : Boolean.TRUE; - } + private static boolean isStatic(PsiModifierListOwner owner) { + if (owner == null) { + return false; + } + if (owner instanceof PsiClass psiClass && ClassUtil.isTopLevelClass(psiClass)) { + return true; + } + PsiModifierList modifierList = owner.getModifierList(); + return modifierList != null && modifierList.hasModifierProperty(PsiModifier.STATIC); + } + + @Nullable + @RequiredReadAction + public static RetentionPolicy getRetentionPolicy(@Nonnull PsiClass annotation) { + PsiModifierList modifierList = annotation.getModifierList(); + if (modifierList != null) { + PsiAnnotation retentionAnno = modifierList.findAnnotation(JavaClassNames.JAVA_LANG_ANNOTATION_RETENTION); + if (retentionAnno == null) { + return RetentionPolicy.CLASS; + } + + if (PsiImplUtil.findAttributeValue(retentionAnno, null) instanceof PsiReference policyRef + && policyRef.resolve() instanceof PsiEnumConstant enumConst) { + String name = enumConst.getName(); + try { + //noinspection ConstantConditions + return Enum.valueOf(RetentionPolicy.class, name); + } + catch (Exception e) { + LOG.warn("Unknown policy: " + name); + } + } + } - @Override - public Boolean visitArrayType(PsiArrayType arrayType) { - if (arrayType.getArrayDimensions() != 1) { - return Boolean.FALSE; - } - PsiType componentType = arrayType.getComponentType(); - return componentType.accept(this); + return null; } - @Override - public Boolean visitClassType(PsiClassType classType) { - if (classType.getParameters().length > 0) { - PsiClassType rawType = classType.rawType(); - return rawType.equalsToText(JavaClassNames.JAVA_LANG_CLASS); - } + public static class AnnotationReturnTypeVisitor extends PsiTypeVisitor { + public static final AnnotationReturnTypeVisitor INSTANCE = new AnnotationReturnTypeVisitor(); - PsiClass aClass = classType.resolve(); - if (aClass != null && (aClass.isAnnotationType() || aClass.isEnum())) { - return Boolean.TRUE; - } + @Override + public Boolean visitType(PsiType type) { + return Boolean.FALSE; + } - return classType.equalsToText(JavaClassNames.JAVA_LANG_CLASS) || classType.equalsToText(JavaClassNames.JAVA_LANG_STRING); - } - } + @Override + public Boolean visitPrimitiveType(PsiPrimitiveType primitiveType) { + return PsiType.VOID.equals(primitiveType) || PsiType.NULL.equals(primitiveType) ? Boolean.FALSE : Boolean.TRUE; + } - private static class DeleteAnnotationAction implements SyntheticIntentionAction { - private final PsiAnnotation myAnnotation; + @Override + public Boolean visitArrayType(PsiArrayType arrayType) { + if (arrayType.getArrayDimensions() != 1) { + return Boolean.FALSE; + } + PsiType componentType = arrayType.getComponentType(); + return componentType.accept(this); + } - private DeleteAnnotationAction(PsiAnnotation annotation) { - myAnnotation = annotation; - } + @Override + public Boolean visitClassType(PsiClassType classType) { + if (classType.getParameters().length > 0) { + PsiClassType rawType = classType.rawType(); + return rawType.equalsToText(JavaClassNames.JAVA_LANG_CLASS); + } - @Nonnull - @Override - public String getText() { - return "Remove"; - } + PsiClass aClass = classType.resolve(); + if (aClass != null && (aClass.isAnnotationType() || aClass.isEnum())) { + return Boolean.TRUE; + } - @Override - public boolean isAvailable(@Nonnull Project project, Editor editor, PsiFile file) { - return true; + return classType.equalsToText(JavaClassNames.JAVA_LANG_CLASS) || classType.equalsToText(JavaClassNames.JAVA_LANG_STRING); + } } - @Override - public void invoke(@Nonnull Project project, Editor editor, PsiFile file) throws IncorrectOperationException { - myAnnotation.delete(); - } + private static class DeleteAnnotationAction implements SyntheticIntentionAction { + private final PsiAnnotation myAnnotation; + + private DeleteAnnotationAction(PsiAnnotation annotation) { + myAnnotation = annotation; + } - @Override - public boolean startInWriteAction() { - return true; + @Nonnull + @Override + public String getText() { + return "Remove"; + } + + @Override + public boolean isAvailable(@Nonnull Project project, Editor editor, PsiFile file) { + return true; + } + + @Override + public void invoke(@Nonnull Project project, Editor editor, PsiFile file) throws IncorrectOperationException { + myAnnotation.delete(); + } + + @Override + public boolean startInWriteAction() { + return true; + } } - } } 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 840bdc8b8..ad338c289 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 @@ -43,7 +43,6 @@ import com.intellij.java.language.psi.javadoc.PsiDocComment; import com.intellij.java.language.psi.util.*; import consulo.annotation.access.RequiredReadAction; -import consulo.component.extension.Extensions; import consulo.document.util.TextRange; import consulo.java.language.impl.localize.JavaErrorLocalize; import consulo.java.language.module.util.JavaClassNames; @@ -137,14 +136,22 @@ public class HighlightUtil extends HighlightUtilBase { ourClassIncompatibleModifiers.put(PsiModifier.NON_SEALED, Set.of(PsiModifier.FINAL, PsiModifier.SEALED)); ourInterfaceIncompatibleModifiers.put(PsiModifier.ABSTRACT, Set.of()); - ourInterfaceIncompatibleModifiers - .put(PsiModifier.PACKAGE_LOCAL, Set.of(PsiModifier.PRIVATE, PsiModifier.PUBLIC, PsiModifier.PROTECTED)); - ourInterfaceIncompatibleModifiers - .put(PsiModifier.PRIVATE, Set.of(PsiModifier.PACKAGE_LOCAL, PsiModifier.PUBLIC, PsiModifier.PROTECTED)); - ourInterfaceIncompatibleModifiers - .put(PsiModifier.PUBLIC, Set.of(PsiModifier.PACKAGE_LOCAL, PsiModifier.PRIVATE, PsiModifier.PROTECTED)); - ourInterfaceIncompatibleModifiers - .put(PsiModifier.PROTECTED, Set.of(PsiModifier.PACKAGE_LOCAL, PsiModifier.PUBLIC, PsiModifier.PRIVATE)); + ourInterfaceIncompatibleModifiers.put( + PsiModifier.PACKAGE_LOCAL, + Set.of(PsiModifier.PRIVATE, PsiModifier.PUBLIC, PsiModifier.PROTECTED) + ); + ourInterfaceIncompatibleModifiers.put( + PsiModifier.PRIVATE, + Set.of(PsiModifier.PACKAGE_LOCAL, PsiModifier.PUBLIC, PsiModifier.PROTECTED) + ); + ourInterfaceIncompatibleModifiers.put( + PsiModifier.PUBLIC, + Set.of(PsiModifier.PACKAGE_LOCAL, PsiModifier.PRIVATE, PsiModifier.PROTECTED) + ); + ourInterfaceIncompatibleModifiers.put( + PsiModifier.PROTECTED, + Set.of(PsiModifier.PACKAGE_LOCAL, PsiModifier.PUBLIC, PsiModifier.PRIVATE) + ); ourInterfaceIncompatibleModifiers.put(PsiModifier.STRICTFP, Set.of()); ourInterfaceIncompatibleModifiers.put(PsiModifier.STATIC, Set.of()); ourInterfaceIncompatibleModifiers.put(PsiModifier.SEALED, Set.of(PsiModifier.NON_SEALED)); @@ -180,8 +187,7 @@ public class HighlightUtil extends HighlightUtilBase { Set.of(PsiModifier.PACKAGE_LOCAL, PsiModifier.PUBLIC, PsiModifier.PRIVATE) ); ourMethodIncompatibleModifiers.put(PsiModifier.STATIC, Set.of(PsiModifier.ABSTRACT, PsiModifier.DEFAULT)); - ourMethodIncompatibleModifiers - .put(PsiModifier.DEFAULT, Set.of(PsiModifier.ABSTRACT, PsiModifier.STATIC, PsiModifier.PRIVATE)); + ourMethodIncompatibleModifiers.put(PsiModifier.DEFAULT, Set.of(PsiModifier.ABSTRACT, PsiModifier.STATIC, PsiModifier.PRIVATE)); ourMethodIncompatibleModifiers.put(PsiModifier.SYNCHRONIZED, Set.of(PsiModifier.ABSTRACT)); ourMethodIncompatibleModifiers.put(PsiModifier.STRICTFP, Set.of(PsiModifier.ABSTRACT)); ourMethodIncompatibleModifiers.put(PsiModifier.FINAL, Set.of(PsiModifier.ABSTRACT)); @@ -335,7 +341,8 @@ public static void registerAccessQuickFixAction( PsiModifier.PUBLIC, }; for (int i = ArrayUtil.indexOf(modifiers, minModifier); i < modifiers.length; i++) { - @PsiModifier.ModifierConstant String modifier = modifiers[i]; + @PsiModifier.ModifierConstant + String modifier = modifiers[i]; modifierListCopy.setModifierProperty(modifier, true); if (facade.getResolveHelper().isAccessible(refElement, modifierListCopy, place, accessObjectClass, fileResolveScope)) { IntentionAction fix = QuickFixFactory.getInstance().createModifierListFix(refElement, modifier, true, true); @@ -440,27 +447,21 @@ public static HighlightInfo checkIntersectionInTypeCast( return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) .range(conjunct) .descriptionAndTooltip(JavaErrorLocalize.interfaceExpected()) - .registerFix( - new FlipIntersectionSidesFix(aClass.getName(), conjList, conjunct, castTypeElement), - null, - null, - null, - null - ) + .registerFix(new FlipIntersectionSidesFix(aClass.getName(), conjList, conjunct, castTypeElement)) .create(); } } else { return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) .range(conjunct) - .descriptionAndTooltip(LocalizeValue.localizeTODO("Unexpected type: class is expected")) + .descriptionAndTooltip(JavaErrorLocalize.unexpectedTypeClassExpected()) .create(); } if (!erasures.add(TypeConversionUtil.erasure(conjType))) { return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) .range(conjunct) - .descriptionAndTooltip(LocalizeValue.localizeTODO("Repeated interface")) - .registerFix(new DeleteRepeatedInterfaceFix(conjunct, conjList), null, null, null, null) + .descriptionAndTooltip(JavaErrorLocalize.repeatedInterface()) + .registerFix(new DeleteRepeatedInterfaceFix(conjunct, conjList)) .create(); } } @@ -480,9 +481,9 @@ public static HighlightInfo checkIntersectionInTypeCast( if (sameGenericParameterization != null) { return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) .range(expression) - .descriptionAndTooltip(LocalizeValue.localizeTODO( - formatClass(sameGenericParameterization) + " cannot be inherited with different arguments: " + - differentArgumentsMessage.get() + .descriptionAndTooltip(JavaErrorLocalize.classCannotBeInheritedWithDifferentArguments( + formatClass(sameGenericParameterization), + differentArgumentsMessage.get() )) .create(); } @@ -781,7 +782,6 @@ public static HighlightInfo checkReturnStatementType(@Nonnull PsiReturnStatement if (parent instanceof PsiCodeFragment) { return null; } - HighlightInfo errorResult = null; if (method == null && lambda != null) { //todo check return statements type inside lambda } @@ -798,20 +798,18 @@ else if (method == null && !(parent instanceof ServerPageFile)) { if (returnValue != null) { PsiType valueType = RefactoringChangeUtil.getTypeByExpression(returnValue); if (isMethodVoid) { - errorResult = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + HighlightInfo.Builder errorResult = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) .range(statement) - .descriptionAndTooltip(JavaErrorLocalize.returnFromVoidMethod()) - .create(); + .descriptionAndTooltip(JavaErrorLocalize.returnFromVoidMethod()); if (valueType != null) { - QuickFixAction.registerQuickFixAction( - errorResult, - QuickFixFactory.getInstance().createMethodReturnFix(method, valueType, true) - ); + errorResult.registerFix(QuickFixFactory.getInstance().createMethodReturnFix(method, valueType, true)); } + return errorResult.create(); } else { TextRange textRange = statement.getTextRange(); - errorResult = checkAssignability(returnType, valueType, returnValue, textRange, returnValue.getStartOffsetInParent()); + HighlightInfo errorResult = + checkAssignability(returnType, valueType, returnValue, textRange, returnValue.getStartOffsetInParent()); if (errorResult != null && valueType != null) { if (!PsiType.VOID.equals(valueType)) { QuickFixAction.registerQuickFixAction( @@ -824,11 +822,14 @@ else if (method == null && !(parent instanceof ServerPageFile)) { PsiType erasedValueType = TypeConversionUtil.erasure(valueType); if (erasedValueType != null && TypeConversionUtil.isAssignable(arrayType.getComponentType(), erasedValueType)) { - QuickFixAction.registerQuickFixAction(errorResult, QuickFixFactory.getInstance() - .createSurroundWithArrayFix(null, returnValue)); + QuickFixAction.registerQuickFixAction( + errorResult, + QuickFixFactory.getInstance().createSurroundWithArrayFix(null, returnValue) + ); } } registerCollectionToArrayFixAction(errorResult, valueType, returnType, returnValue); + return errorResult; } } } @@ -837,11 +838,11 @@ else if (!isMethodVoid) { .range(statement) .descriptionAndTooltip(JavaErrorLocalize.missingReturnValue()) .navigationShift(PsiKeyword.RETURN.length()) - .registerFix(QuickFixFactory.getInstance().createMethodReturnFix(method, PsiType.VOID, true), null, null, null, null) + .registerFix(QuickFixFactory.getInstance().createMethodReturnFix(method, PsiType.VOID, true)) .create(); } } - return errorResult; + return null; } private static void registerCollectionToArrayFixAction( @@ -891,17 +892,13 @@ public static HighlightInfo checkVariableAlreadyDefined(@Nonnull PsiVariable var if (oldVariable != null) { PsiIdentifier identifier = variable.getNameIdentifier(); assert identifier != null : variable; - HighlightInfo highlightInfo = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + HighlightInfo.Builder highlightInfo = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) .range(identifier) - .descriptionAndTooltip(JavaErrorLocalize.variableAlreadyDefined(variable.getName())) - .create(); + .descriptionAndTooltip(JavaErrorLocalize.variableAlreadyDefined(variable.getName())); if (variable instanceof PsiLocalVariable localVar) { - QuickFixAction.registerQuickFixAction( - highlightInfo, - QuickFixFactory.getInstance().createReuseVariableDeclarationFix(localVar) - ); + highlightInfo.registerFix(QuickFixFactory.getInstance().createReuseVariableDeclarationFix(localVar)); } - return highlightInfo; + return highlightInfo.create(); } return null; } @@ -968,12 +965,10 @@ public static HighlightInfo checkUnhandledExceptions(@Nonnull PsiElement element if (textRange == null) { textRange = element.getTextRange(); } - HighlightInfo errorResult = HighlightInfo.newHighlightInfo(highlightType) + HighlightInfo.Builder errorResult = HighlightInfo.newHighlightInfo(highlightType) .range(textRange) - .descriptionAndTooltip(getUnhandledExceptionsDescriptor(unhandledExceptions)) - .create(); - registerUnhandledExceptionFixes(element, errorResult, unhandledExceptions); - return errorResult; + .descriptionAndTooltip(getUnhandledExceptionsDescriptor(unhandledExceptions)); + return registerUnhandledExceptionFixes(element, errorResult, unhandledExceptions).create(); } @Nullable @@ -989,28 +984,26 @@ public static HighlightInfo checkUnhandledCloserExceptions(@Nonnull PsiResourceL return null; } - HighlightInfo highlight = HighlightInfo.newHighlightInfo(highlightType) + HighlightInfo.Builder highlight = HighlightInfo.newHighlightInfo(highlightType) .range(resource) - .descriptionAndTooltip(getUnhandledExceptionsDescriptor(unhandled, "auto-closeable resource")) - .create(); - registerUnhandledExceptionFixes(resource, highlight, unhandled); - return highlight; + .descriptionAndTooltip(getUnhandledExceptionsDescriptor(unhandled, "auto-closeable resource")); + return registerUnhandledExceptionFixes(resource, highlight, unhandled).create(); } - private static void registerUnhandledExceptionFixes(PsiElement element, HighlightInfo errorResult, List unhandled) { - QuickFixAction.registerQuickFixAction(errorResult, QuickFixFactory.getInstance().createAddExceptionToCatchFix()); - QuickFixAction.registerQuickFixAction(errorResult, QuickFixFactory.getInstance().createAddExceptionToThrowsFix(element)); - QuickFixAction.registerQuickFixAction( - errorResult, - QuickFixFactory.getInstance().createAddExceptionFromFieldInitializerToConstructorThrowsFix(element) - ); - QuickFixAction.registerQuickFixAction(errorResult, QuickFixFactory.getInstance().createSurroundWithTryCatchFix(element)); + private static HighlightInfo.Builder registerUnhandledExceptionFixes( + PsiElement element, + HighlightInfo.Builder errorResult, + List unhandled + ) { + QuickFixFactory factory = QuickFixFactory.getInstance(); + errorResult.registerFix(factory.createAddExceptionToCatchFix()) + .registerFix(factory.createAddExceptionToThrowsFix(element)) + .registerFix(factory.createAddExceptionFromFieldInitializerToConstructorThrowsFix(element)) + .registerFix(factory.createSurroundWithTryCatchFix(element)); if (unhandled.size() == 1) { - QuickFixAction.registerQuickFixAction( - errorResult, - QuickFixFactory.getInstance().createGeneralizeCatchFix(element, unhandled.get(0)) - ); + errorResult.registerFix(factory.createGeneralizeCatchFix(element, unhandled.get(0))); } + return errorResult; } @Nullable @@ -1079,13 +1072,11 @@ public static HighlightInfo checkIllegalModifierCombination(@Nonnull PsiKeyword @PsiModifier.ModifierConstant String modifier = keyword.getText(); String incompatible = getIncompatibleModifier(modifier, modifierList); if (incompatible != null) { - HighlightInfo highlightInfo = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) .range(keyword) .descriptionAndTooltip(JavaErrorLocalize.incompatibleModifiers(modifier, incompatible)) + .registerFix(QuickFixFactory.getInstance().createModifierListFix(modifierList, modifier, false, false)) .create(); - QuickFixAction.registerQuickFixAction(highlightInfo, QuickFixFactory.getInstance() - .createModifierListFix(modifierList, modifier, false, false)); - return highlightInfo; } return null; @@ -1228,7 +1219,7 @@ else if (modifierOwner instanceof PsiReceiverParameter) { return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) .range(keyword) .descriptionAndTooltip(JavaErrorLocalize.modifierNotAllowed(modifier)) - .registerFix(QuickFixFactory.getInstance().createModifierListFix(modifierList, modifier, false, false), null, null, null, null) + .registerFix(QuickFixFactory.getInstance().createModifierListFix(modifierList, modifier, false, false)) .create(); } @@ -1370,7 +1361,7 @@ else if (type == JavaTokenType.CHARACTER_LITERAL) { return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) .range(expression) .descriptionAndTooltip(JavaErrorLocalize.tooManyCharactersInCharacterLiteral()) - .registerFix(QuickFixFactory.getInstance().createConvertToStringLiteralAction(), null, null, null, null) + .registerFix(QuickFixFactory.getInstance().createConvertToStringLiteralAction()) .create(); } else if (length == 0) { @@ -1649,7 +1640,7 @@ private static HighlightInfo checkSimpleCatchParameter( return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) .range(parameter) .descriptionAndTooltip(JavaErrorLocalize.exceptionNeverThrownTry(JavaHighlightUtil.formatType(caughtType))) - .registerFix(QuickFixFactory.getInstance().createDeleteCatchFix(parameter), null, null, null, null) + .registerFix(QuickFixFactory.getInstance().createDeleteCatchFix(parameter)) .create(); } @@ -1679,7 +1670,7 @@ private static List checkMultiCatchParameter( HighlightInfo highlight = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) .range(typeElement) .descriptionAndTooltip(JavaErrorLocalize.exceptionNeverThrownTry(JavaHighlightUtil.formatType(catchType))) - .registerFix(QuickFixFactory.getInstance().createDeleteMultiCatchFix(typeElement), null, null, null, null) + .registerFix(QuickFixFactory.getInstance().createDeleteMultiCatchFix(typeElement)) .create(); highlights.add(highlight); } @@ -1748,16 +1739,12 @@ public static Collection checkWithImprovedCatchAnalysis( HighlightInfo highlightInfo = HighlightInfo.newHighlightInfo(HighlightInfoType.WARNING) .range(catchSection) .descriptionAndTooltip(JavaErrorLocalize.exceptionAlreadyCaughtWarn(formatTypes(caughtCopy), caughtCopy.size())) + .registerFix( + isMultiCatch + ? QuickFixFactory.getInstance().createDeleteMultiCatchFix(catchTypeElement) + : QuickFixFactory.getInstance().createDeleteCatchFix(parameter) + ) .create(); - if (isMultiCatch) { - QuickFixAction.registerQuickFixAction( - highlightInfo, - QuickFixFactory.getInstance().createDeleteMultiCatchFix(catchTypeElement) - ); - } - else { - QuickFixAction.registerQuickFixAction(highlightInfo, QuickFixFactory.getInstance().createDeleteCatchFix(parameter)); - } result.add(highlightInfo); } } @@ -1775,20 +1762,16 @@ public static HighlightInfo checkNotAStatement(@Nonnull PsiStatement statement) isDeclarationNotAllowed = parent instanceof PsiIfStatement || parent instanceof PsiLoopStatement; } - String description = isDeclarationNotAllowed - ? JavaErrorBundle.message("declaration.not.allowed") - : JavaErrorBundle.message("not.a.statement"); - HighlightInfo error = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + LocalizeValue description = isDeclarationNotAllowed + ? JavaErrorLocalize.declarationNotAllowed() + : JavaErrorLocalize.notAStatement(); + HighlightInfo.Builder error = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) .range(statement) - .descriptionAndTooltip(description) - .create(); + .descriptionAndTooltip(description); if (statement instanceof PsiExpressionStatement expressionStmt) { - QuickFixAction.registerQuickFixAction( - error, - QuickFixFactory.getInstance().createDeleteSideEffectAwareFix(expressionStmt) - ); + error.registerFix(QuickFixFactory.getInstance().createDeleteSideEffectAwareFix(expressionStmt)); } - return error; + return error.create(); } return null; } @@ -1855,21 +1838,17 @@ else if (element instanceof PsiStatement statement) { if (enhancedLabels && !(alien instanceof PsiSwitchLabelStatementBase)) { PsiSwitchLabeledRuleStatement previousRule = PsiTreeUtil.getPrevSiblingOfType(alien, PsiSwitchLabeledRuleStatement.class); - HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + HighlightInfo.Builder info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) .range(alien) - .descriptionAndTooltip(JavaErrorLocalize.statementMustBePrependedWithCaseLabel()) - .create(); + .descriptionAndTooltip(JavaErrorLocalize.statementMustBePrependedWithCaseLabel()); if (previousRule != null) { - QuickFixAction.registerQuickFixAction( - info, - QuickFixFactory.getInstance().createWrapSwitchRuleStatementsIntoBlockFix(previousRule) - ); + info.registerFix(QuickFixFactory.getInstance().createWrapSwitchRuleStatementsIntoBlockFix(previousRule)); } - return info; + return info.create(); } return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) .range(alien) - .descriptionAndTooltip(JavaErrorBundle.message("different.case.kinds.in.switch")) + .descriptionAndTooltip(JavaErrorLocalize.differentCaseKindsInSwitch()) .create(); } } @@ -2050,7 +2029,8 @@ else if (resolved != null) { } else { aClass = PsiTreeUtil.getParentOfType(expr, PsiClass.class); - if (aClass instanceof PsiAnonymousClass anonymousClass && PsiTreeUtil.isAncestor(anonymousClass.getArgumentList(), expr, false)) { + if (aClass instanceof PsiAnonymousClass anonymousClass + && PsiTreeUtil.isAncestor(anonymousClass.getArgumentList(), expr, false)) { aClass = PsiTreeUtil.getParentOfType(aClass, PsiClass.class, true); } } @@ -2321,7 +2301,7 @@ public static HighlightInfo checkValidArrayAccessExpression(@Nonnull PsiArrayAcc return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) .range(arrayExpression) .descriptionAndTooltip(JavaErrorLocalize.arrayTypeExpected(JavaHighlightUtil.formatType(arrayExpressionType))) - .registerFix(QuickFixFactory.getInstance().createReplaceWithListAccessFix(arrayAccessExpression), null, null, null, null) + .registerFix(QuickFixFactory.getInstance().createReplaceWithListAccessFix(arrayAccessExpression)) .create(); } @@ -2388,13 +2368,13 @@ public static HighlightInfo checkResourceVariableIsFinal(@Nonnull PsiResourceExp return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) .range(expression) - .descriptionAndTooltip(JavaErrorBundle.message("resource.variable.must.be.final")) + .descriptionAndTooltip(JavaErrorLocalize.resourceVariableMustBeFinal()) .create(); } return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) .range(expression) - .descriptionAndTooltip(JavaErrorBundle.message("declaration.or.variable.expected")) + .descriptionAndTooltip(JavaErrorLocalize.declarationOrVariableExpected()) .create(); } @@ -2440,7 +2420,7 @@ private static HighlightInfo checkArrayInitializerCompatibleTypes(@Nonnull PsiEx if (initializerType == null) { return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) .range(initializer) - .descriptionAndTooltip(JavaErrorBundle.message("illegal.initializer", JavaHighlightUtil.formatType(componentType))) + .descriptionAndTooltip(JavaErrorLocalize.illegalInitializer(JavaHighlightUtil.formatType(componentType))) .create(); } PsiExpression expression = initializer instanceof PsiArrayInitializerExpression ? null : initializer; @@ -2498,7 +2478,7 @@ else if (parent instanceof PsiNewExpression || parent instanceof PsiArrayInitial return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) .range(expression) .descriptionAndTooltip(JavaErrorLocalize.arrayInitializerNotAllowed()) - .registerFix(QuickFixFactory.getInstance().createAddNewArrayExpressionFix(expression), null, null, null, null) + .registerFix(QuickFixFactory.getInstance().createAddNewArrayExpressionFix(expression)) .create(); } @@ -2620,9 +2600,9 @@ public static Collection checkSwitchLabelValues(@Nonnull PsiSwitc } } if (!exhaustive) { - String message = values.isEmpty() - ? JavaErrorBundle.message("switch.expr.empty") - : JavaErrorBundle.message("switch.expr.incomplete"); + LocalizeValue message = values.isEmpty() + ? JavaErrorLocalize.switchExprEmpty() + : JavaErrorLocalize.switchExprIncomplete(); HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) .range(ObjectUtil.notNull(selectorExpression, switchBlock)) .descriptionAndTooltip(message) @@ -2641,7 +2621,6 @@ public static Collection checkSwitchLabelValues(@Nonnull PsiSwitc return results; } - /** * see JLS 8.3.2.3 */ @@ -3197,7 +3176,7 @@ public static Collection checkCatchTypeIsDisjoint(@Nonnull PsiPar HighlightInfo highlight = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) .range(element) .descriptionAndTooltip(JavaErrorLocalize.exceptionMustBeDisjoint(sub ? name1 : name2, sub ? name2 : name1).get()) - .registerFix(QuickFixFactory.getInstance().createDeleteMultiCatchFix(element), null, null, null, null) + .registerFix(QuickFixFactory.getInstance().createDeleteMultiCatchFix(element)) .create(); result.add(highlight); break; @@ -3245,25 +3224,14 @@ public static Collection checkExceptionAlreadyCaught(@Nonnull Psi HighlightInfo highlightInfo = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) .range(typeElement) .descriptionAndTooltip(JavaErrorLocalize.exceptionAlreadyCaught(className)) + .registerFix(QuickFixFactory.getInstance().createMoveCatchUpFix(catchSection, upperCatchSection)) .registerFix( - QuickFixFactory.getInstance().createMoveCatchUpFix(catchSection, upperCatchSection), - null, - null, - null, - null + isInMultiCatch + ? QuickFixFactory.getInstance().createDeleteMultiCatchFix(typeElement) + : QuickFixFactory.getInstance().createDeleteCatchFix(parameter) ) .create(); result.add(highlightInfo); - - if (isInMultiCatch) { - QuickFixAction.registerQuickFixAction( - highlightInfo, - QuickFixFactory.getInstance().createDeleteMultiCatchFix(typeElement) - ); - } - else { - QuickFixAction.registerQuickFixAction(highlightInfo, QuickFixFactory.getInstance().createDeleteCatchFix(parameter)); - } } } } @@ -3589,7 +3557,7 @@ public static HighlightInfo checkReference( if (qualifierExpression == ref && resolved != null && !(resolved instanceof PsiClass) && !(resolved instanceof PsiVariable)) { return HighlightInfo.newHighlightInfo(HighlightInfoType.WRONG_REF) .range(qualifierExpression) - .descriptionAndTooltip(JavaErrorBundle.message("qualifier.must.be.expression")) + .descriptionAndTooltip(JavaErrorLocalize.qualifierMustBeExpression()) .create(); } } @@ -3799,14 +3767,8 @@ public static HighlightInfo checkClassReferenceAfterQualifier(@Nonnull PsiRefere } 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 - ) + .descriptionAndTooltip(JavaErrorLocalize.expectedClassOrPackage()) + .registerFix(QuickFixFactory.getInstance().createRemoveQualifierFix(qualifier, expression, resolvedClass)) .create(); } @@ -3844,9 +3806,8 @@ public static List getChangeVariableTypeFixes(@Nonnull PsiVaria } List result = new ArrayList<>(); if (itemType != null) { - for (ChangeVariableTypeQuickFixProvider fixProvider : Extensions.getExtensions(ChangeVariableTypeQuickFixProvider.EP_NAME)) { - Collections.addAll(result, fixProvider.getFixes(parameter, itemType)); - } + parameter.getApplication().getExtensionPoint(ChangeVariableTypeQuickFixProvider.class) + .forEach(fixProvider -> Collections.addAll(result, fixProvider.getFixes(parameter, itemType))); } IntentionAction changeFix = getChangeParameterClassFix(parameter.getType(), itemType); if (changeFix != null) { @@ -3863,7 +3824,7 @@ public static HighlightInfo checkAnnotationMethodParameters(@Nonnull PsiParamete return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) .range(list) .descriptionAndTooltip(JavaErrorLocalize.annotationInterfaceMembersMayNotHaveParameters()) - .registerFix(QuickFixFactory.getInstance().createRemoveParameterListFix((PsiMethod)parent), null, null, null, null) + .registerFix(QuickFixFactory.getInstance().createRemoveParameterListFix((PsiMethod)parent)) .create(); } return null; @@ -3873,9 +3834,12 @@ public static HighlightInfo checkAnnotationMethodParameters(@Nonnull PsiParamete @RequiredReadAction public static HighlightInfo checkForStatement(@Nonnull PsiForStatement statement) { PsiStatement init = statement.getInitialization(); - if (init == null || init instanceof PsiEmptyStatement - || init instanceof PsiDeclarationStatement declaration && ArrayUtil.getFirstElement(declaration.getDeclaredElements()) - instanceof PsiLocalVariable || init instanceof PsiExpressionStatement || init instanceof PsiExpressionListStatement) { + if (init == null + || init instanceof PsiEmptyStatement + || init instanceof PsiDeclarationStatement declaration + && ArrayUtil.getFirstElement(declaration.getDeclaredElements()) instanceof PsiLocalVariable + || init instanceof PsiExpressionStatement + || init instanceof PsiExpressionListStatement) { return null; } @@ -3965,14 +3929,8 @@ public static HighlightInfo checkFeature( 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) + .registerFix(QuickFixFactory.getInstance().createIncreaseLanguageLevelFix(feature.getMinimumLevel())) + .registerFix(QuickFixFactory.getInstance().createShowModulePropertiesFix(element)) .create(); } @@ -3988,14 +3946,19 @@ private static LocalizeValue getUnsupportedFeatureMessage(PsiElement element, Ja if (module != null) { LanguageLevel moduleLanguageLevel = EffectiveLanguageLevelUtil.getEffectiveLanguageLevel(module); if (moduleLanguageLevel.isAtLeast(feature.getMinimumLevel())) { - for (FilePropertyPusher pusher : FilePropertyPusher.EP_NAME.getExtensionList()) { - if (pusher instanceof JavaLanguageLevelPusher languageLevelPusher) { - LocalizeValue newMessage = languageLevelPusher.getInconsistencyLanguageLevelMessage(message, element, level, file); - if (newMessage != LocalizeValue.empty()) { - return newMessage; + return module.getApplication().getExtensionPoint(FilePropertyPusher.class).computeSafeIfAny( + pusher -> { + if (pusher instanceof JavaLanguageLevelPusher languageLevelPusher) { + LocalizeValue newMessage = + languageLevelPusher.getInconsistencyLanguageLevelMessage(message, element, level, file); + if (newMessage != LocalizeValue.empty()) { + return newMessage; + } } - } - } + return null; + }, + message + ); } } 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 2e8fad10c..e5a6f1a79 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 @@ -93,14 +93,14 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh private final PsiElementVisitor REGISTER_REFERENCES_VISITOR = new PsiRecursiveElementWalkingVisitor() { @Override + @RequiredReadAction public void visitElement(PsiElement element) { super.visitElement(element); for (PsiReference reference : element.getReferences()) { - PsiElement resolved = reference.resolve(); - if (resolved instanceof PsiNamedElement) { - myRefCountHolder.registerLocallyReferenced((PsiNamedElement)resolved); - if (resolved instanceof PsiMember) { - myRefCountHolder.registerReference(reference, new CandidateInfo(resolved, PsiSubstitutor.EMPTY)); + if (reference.resolve() instanceof PsiNamedElement namedElem) { + myRefCountHolder.registerLocallyReferenced(namedElem); + if (namedElem instanceof PsiMember member) { + myRefCountHolder.registerReference(reference, new CandidateInfo(member, PsiSubstitutor.EMPTY)); } } } @@ -137,12 +137,14 @@ public void visit(@Nonnull PsiElement element) { element.accept(this); } + @RequiredReadAction private void registerReferencesFromInjectedFragments(@Nonnull PsiElement element) { InjectedLanguageManager manager = InjectedLanguageManager.getInstance(myFile.getProject()); manager.enumerateEx(element, myFile, false, (injectedPsi, places) -> injectedPsi.accept(REGISTER_REFERENCES_VISITOR)); } @Override + @RequiredReadAction public boolean analyze( @Nonnull PsiFile file, boolean updateWholeFile, @@ -203,10 +205,12 @@ public boolean analyze( return true; } + @RequiredReadAction protected void prepareToRunAsInspection(@Nonnull HighlightInfoHolder holder) { prepare(holder, holder.getContextFile()); } + @RequiredReadAction private void prepare(HighlightInfoHolder holder, PsiFile file) { myHolder = holder; myFile = file; @@ -238,14 +242,14 @@ public void visitElement(PsiElement element) { } @Nullable + @RequiredReadAction public static JavaResolveResult resolveJavaReference(@Nonnull PsiReference reference) { - if (reference instanceof PsiJavaReference) { - PsiJavaReference psiJavaReference = (PsiJavaReference)reference; - return psiJavaReference.advancedResolve(false); + if (reference instanceof PsiJavaReference javaRef) { + return javaRef.advancedResolve(false); } - if (reference instanceof PsiPolyVariantReference && - reference instanceof ResolvingHint && ((ResolvingHint)reference).canResolveTo(PsiClass.class)) { - ResolveResult[] resolve = ((PsiPolyVariantReference)reference).multiResolve(false); + if (reference instanceof PsiPolyVariantReference polyVariantReference && + reference instanceof ResolvingHint hint && hint.canResolveTo(PsiClass.class)) { + ResolveResult[] resolve = polyVariantReference.multiResolve(false); if (resolve.length == 1 && resolve[0] instanceof JavaResolveResult) { return (JavaResolveResult)resolve[0]; } @@ -254,7 +258,8 @@ public static JavaResolveResult resolveJavaReference(@Nonnull PsiReference refer } @Override - public void visitAnnotation(PsiAnnotation annotation) { + @RequiredReadAction + public void visitAnnotation(@Nonnull PsiAnnotation annotation) { super.visitAnnotation(annotation); if (!myHolder.hasErrorResults()) { myHolder.add(checkFeature(annotation, JavaFeature.ANNOTATIONS)); @@ -282,14 +287,15 @@ public void visitAnnotation(PsiAnnotation annotation) { } if (JavaClassNames.JAVA_LANG_OVERRIDE.equals(annotation.getQualifiedName())) { PsiAnnotationOwner owner = annotation.getOwner(); - PsiElement parent = owner instanceof PsiModifierList ? ((PsiModifierList)owner).getParent() : null; - if (parent instanceof PsiMethod) { - myHolder.add(GenericsHighlightUtil.checkOverrideAnnotation((PsiMethod)parent, annotation, myLanguageLevel)); + PsiElement parent = owner instanceof PsiModifierList modifierList ? modifierList.getParent() : null; + if (parent instanceof PsiMethod method) { + myHolder.add(GenericsHighlightUtil.checkOverrideAnnotation(method, annotation, myLanguageLevel)); } } } @Override + @RequiredReadAction public void visitAnnotationArrayInitializer(PsiArrayInitializerMemberValue initializer) { PsiMethod method = null; @@ -306,8 +312,8 @@ else if (PsiUtil.isAnnotationMethod(parent)) { if (method != null) { PsiType type = method.getReturnType(); - if (type instanceof PsiArrayType) { - type = ((PsiArrayType)type).getComponentType(); + if (type instanceof PsiArrayType arrayType) { + type = arrayType.getComponentType(); PsiAnnotationMemberValue[] initializers = initializer.getInitializers(); for (PsiAnnotationMemberValue initializer1 : initializers) { myHolder.add(AnnotationsHighlightUtil.checkMemberValueType(initializer1, type)); @@ -317,6 +323,7 @@ else if (PsiUtil.isAnnotationMethod(parent)) { } @Override + @RequiredReadAction public void visitAnnotationMethod(PsiAnnotationMethod method) { PsiType returnType = method.getReturnType(); PsiAnnotationMemberValue value = method.getDefaultValue(); @@ -335,7 +342,8 @@ public void visitAnnotationMethod(PsiAnnotationMethod method) { } @Override - public void visitArrayInitializerExpression(PsiArrayInitializerExpression expression) { + @RequiredReadAction + public void visitArrayInitializerExpression(@Nonnull PsiArrayInitializerExpression expression) { super.visitArrayInitializerExpression(expression); if (!myHolder.hasErrorResults()) { myHolder.add(HighlightUtil.checkArrayInitializerApplicable(expression)); @@ -348,7 +356,8 @@ public void visitArrayInitializerExpression(PsiArrayInitializerExpression expres } @Override - public void visitAssignmentExpression(PsiAssignmentExpression assignment) { + @RequiredReadAction + public void visitAssignmentExpression(@Nonnull PsiAssignmentExpression assignment) { if (!myHolder.hasErrorResults()) { myHolder.add(HighlightUtil.checkAssignmentCompatibleTypes(assignment)); } @@ -361,7 +370,8 @@ public void visitAssignmentExpression(PsiAssignmentExpression assignment) { } @Override - public void visitPolyadicExpression(PsiPolyadicExpression expression) { + @RequiredReadAction + public void visitPolyadicExpression(@Nonnull PsiPolyadicExpression expression) { super.visitPolyadicExpression(expression); if (!myHolder.hasErrorResults()) { myHolder.add(HighlightUtil.checkPolyadicOperatorApplicable(expression)); @@ -369,7 +379,8 @@ public void visitPolyadicExpression(PsiPolyadicExpression expression) { } @Override - public void visitLambdaExpression(PsiLambdaExpression expression) { + @RequiredReadAction + public void visitLambdaExpression(@Nonnull PsiLambdaExpression expression) { myHolder.add(checkFeature(expression, JavaFeature.LAMBDA_EXPRESSIONS)); final PsiElement parent = PsiUtil.skipParenthesizedExprUp(expression.getParent()); if (parent instanceof PsiExpressionStatement) { @@ -407,13 +418,13 @@ else if (LambdaUtil.getFunctionalInterfaceType(expression, true) != null) { if (!myHolder.hasErrorResults() && functionalInterfaceType != null) { String parentInferenceErrorMessage = null; - final PsiCallExpression callExpression = - parent instanceof PsiExpressionList && parent.getParent() instanceof PsiCallExpression ? (PsiCallExpression)parent.getParent() : null; - final JavaResolveResult containingCallResolveResult = callExpression != null ? callExpression.resolveMethodGenerics() : null; - if (containingCallResolveResult instanceof MethodCandidateInfo) { - parentInferenceErrorMessage = ((MethodCandidateInfo)containingCallResolveResult).getInferenceErrorMessage(); + PsiCallExpression callExpression = + parent instanceof PsiExpressionList && parent.getParent() instanceof PsiCallExpression call ? call : null; + JavaResolveResult containingCallResolveResult = callExpression != null ? callExpression.resolveMethodGenerics() : null; + if (containingCallResolveResult instanceof MethodCandidateInfo methodCandidateInfo) { + parentInferenceErrorMessage = methodCandidateInfo.getInferenceErrorMessage(); } - final Map returnErrors = + Map returnErrors = LambdaUtil.checkReturnTypeCompatible(expression, LambdaUtil.getFunctionalInterfaceReturnType(functionalInterfaceType)); if (parentInferenceErrorMessage != null && (returnErrors == null || !returnErrors.containsValue(parentInferenceErrorMessage))) { myHolder.add(HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) @@ -432,10 +443,10 @@ else if (returnErrors != null) { } if (!myHolder.hasErrorResults() && functionalInterfaceType != null) { - final PsiClassType.ClassResolveResult resolveResult = PsiUtil.resolveGenericsClassInType(functionalInterfaceType); - final PsiMethod interfaceMethod = LambdaUtil.getFunctionalInterfaceMethod(resolveResult); + PsiClassType.ClassResolveResult resolveResult = PsiUtil.resolveGenericsClassInType(functionalInterfaceType); + PsiMethod interfaceMethod = LambdaUtil.getFunctionalInterfaceMethod(resolveResult); if (interfaceMethod != null) { - final PsiParameter[] parameters = interfaceMethod.getParameterList().getParameters(); + PsiParameter[] parameters = interfaceMethod.getParameterList().getParameters(); myHolder.add(LambdaHighlightingUtil.checkParametersCompatible( expression, parameters, @@ -445,7 +456,7 @@ else if (returnErrors != null) { } if (!myHolder.hasErrorResults()) { - final PsiElement body = expression.getBody(); + PsiElement body = expression.getBody(); if (body instanceof PsiCodeBlock) { myHolder.add(HighlightControlFlowUtil.checkUnreachableStatement((PsiCodeBlock)body)); } @@ -547,16 +558,16 @@ public void visitJavaToken(PsiJavaToken token) { super.visitJavaToken(token); if (!myHolder.hasErrorResults() && token.getTokenType() == JavaTokenType.RBRACE && token.getParent() instanceof PsiCodeBlock) { - final PsiElement gParent = token.getParent().getParent(); - final PsiCodeBlock codeBlock; - final PsiType returnType; + PsiElement gParent = token.getParent().getParent(); + PsiCodeBlock codeBlock; + PsiType returnType; if (gParent instanceof PsiMethod) { PsiMethod method = (PsiMethod)gParent; codeBlock = method.getBody(); returnType = method.getReturnType(); } else if (gParent instanceof PsiLambdaExpression) { - final PsiElement body = ((PsiLambdaExpression)gParent).getBody(); + PsiElement body = ((PsiLambdaExpression)gParent).getBody(); if (!(body instanceof PsiCodeBlock)) { return; } @@ -571,18 +582,20 @@ else if (gParent instanceof PsiLambdaExpression) { } @Override - public void visitDocComment(PsiDocComment comment) { + @RequiredReadAction + public void visitDocComment(@Nonnull PsiDocComment comment) { if (!myHolder.hasErrorResults()) { myHolder.add(HighlightUtil.checkUnclosedComment(comment)); } } @Override + @RequiredReadAction public void visitDocTagValue(PsiDocTagValue value) { PsiReference reference = value.getReference(); if (reference != null) { PsiElement element = reference.resolve(); - final TextAttributesScheme colorsScheme = myHolder.getColorsScheme(); + TextAttributesScheme colorsScheme = myHolder.getColorsScheme(); if (element instanceof PsiMethod) { PsiElement nameElement = ((PsiDocMethodOrFieldRef)value).getNameElement(); if (nameElement != null) { @@ -2152,7 +2165,8 @@ public void visitReceiverParameter(PsiReceiverParameter parameter) { } @Override - public void visitModule(PsiJavaModule module) { + @RequiredReadAction + public void visitModule(@Nonnull PsiJavaModule module) { super.visitModule(module); if (!myHolder.hasErrorResults()) { myHolder.add(checkFeature(module, JavaFeature.MODULES)); @@ -2178,7 +2192,8 @@ public void visitModule(PsiJavaModule module) { } @Override - public void visitRequiresStatement(PsiRequiresStatement statement) { + @RequiredReadAction + public void visitRequiresStatement(@Nonnull PsiRequiresStatement statement) { super.visitRequiresStatement(statement); if (myLanguageLevel.isAtLeast(LanguageLevel.JDK_1_9)) { PsiJavaModule container = (PsiJavaModule)statement.getParent(); @@ -2190,7 +2205,8 @@ public void visitRequiresStatement(PsiRequiresStatement statement) { } @Override - public void visitPackageAccessibilityStatement(PsiPackageAccessibilityStatement statement) { + @RequiredReadAction + public void visitPackageAccessibilityStatement(@Nonnull PsiPackageAccessibilityStatement statement) { super.visitPackageAccessibilityStatement(statement); if (myLanguageLevel.isAtLeast(LanguageLevel.JDK_1_9)) { if (!myHolder.hasErrorResults()) { @@ -2206,7 +2222,8 @@ public void visitPackageAccessibilityStatement(PsiPackageAccessibilityStatement } @Override - public void visitUsesStatement(PsiUsesStatement statement) { + @RequiredReadAction + public void visitUsesStatement(@Nonnull PsiUsesStatement statement) { super.visitUsesStatement(statement); if (myLanguageLevel.isAtLeast(LanguageLevel.JDK_1_9)) { if (!myHolder.hasErrorResults()) { @@ -2216,7 +2233,8 @@ public void visitUsesStatement(PsiUsesStatement statement) { } @Override - public void visitProvidesStatement(PsiProvidesStatement statement) { + @RequiredReadAction + public void visitProvidesStatement(@Nonnull PsiProvidesStatement statement) { super.visitProvidesStatement(statement); if (myLanguageLevel.isAtLeast(LanguageLevel.JDK_1_9)) { if (!myHolder.hasErrorResults()) { @@ -2226,6 +2244,7 @@ public void visitProvidesStatement(PsiProvidesStatement statement) { } @Nullable + @RequiredReadAction private HighlightInfo checkFeature(@Nonnull PsiElement element, @Nonnull JavaFeature feature) { return HighlightUtil.checkFeature(element, feature, myLanguageLevel, myFile); } diff --git a/java-language-impl/src/main/resources/LOCALIZE-LIB/en_US/consulo.java.language.impl.JavaErrorLocalize.yaml b/java-language-impl/src/main/resources/LOCALIZE-LIB/en_US/consulo.java.language.impl.JavaErrorLocalize.yaml index 6cd86d92c..0b53b2675 100644 --- a/java-language-impl/src/main/resources/LOCALIZE-LIB/en_US/consulo.java.language.impl.JavaErrorLocalize.yaml +++ b/java-language-impl/src/main/resources/LOCALIZE-LIB/en_US/consulo.java.language.impl.JavaErrorLocalize.yaml @@ -21,7 +21,7 @@ annotation.non.constant.attribute.value: annotation.non.class.literal.attribute.value: text: Attribute value must be a class literal annotation.invalid.annotation.member.type: - text: Invalid type for annotation member + text: Invalid type ''{0}'' for annotation member annotation.cyclic.element.type: text: Cyclic annotation element type annotation.annotation.type.expected: @@ -801,4 +801,40 @@ safevarargs.not.suppress.potentially.unsafe.operations: safevarargs.not.applicable.for.reifiable.types: text: "@SafeVarargs is not applicable for reifiable types" safevarargs.not.allowed.non.final.instance.methods: - text: "@SafeVarargs is not allowed on non-final instance methods" \ No newline at end of file + text: "@SafeVarargs is not allowed on non-final instance methods" +qualifier.must.be.expression: + text: Qualifier must be an expression +expected.class.or.package: + text: Expected class or package +unexpected.type.class.expected: + text: "Unexpected type: class is expected" +repeated.interface: + text: Repeated interface +class.cannot.be.inherited.with.different.arguments: + text: "{0} cannot be inherited with different arguments: {1}" +declaration.not.allowed: + text: Declaration not allowed here +different.case.kinds.in.switch: + text: Different case kinds used in the switch +resource.variable.must.be.final: + text: Variable used as a try-with-resources resource should be final or effectively final +declaration.or.variable.expected: + text: Declaration, final or effectively final variable expected +illegal.initializer: + text: Illegal initializer for ''{0}'' +switch.expr.empty: + text: "'switch' expression does not have any case clauses" +switch.expr.incomplete: + text: "'switch' expression does not cover all possible input values" +illegal.self.reference: + text: "Cannot read value of field ''{0}'' from inside the fields''s definition" +receiver.wrong.context: + text: Receivers are not allowed outside of method parameter list +receiver.static.context: + text: The receiver cannot be used in a static context +receiver.wrong.position: + text: The receiver should be the first parameter +receiver.type.mismatch: + text: The receiver type does not match the enclosing class type +receiver.name.mismatch: + text: The receiver name does not match the enclosing class type \ No newline at end of file