diff --git a/java-analysis-api/src/main/resources/LOCALIZE-LIB/en_US/consulo.java.analysis.JavaAnalysisLocalize.yaml b/java-analysis-api/src/main/resources/LOCALIZE-LIB/en_US/consulo.java.analysis.JavaAnalysisLocalize.yaml
index 275842ee7..6cf05e8c4 100644
--- a/java-analysis-api/src/main/resources/LOCALIZE-LIB/en_US/consulo.java.analysis.JavaAnalysisLocalize.yaml
+++ b/java-analysis-api/src/main/resources/LOCALIZE-LIB/en_US/consulo.java.analysis.JavaAnalysisLocalize.yaml
@@ -30,6 +30,8 @@ change.visibility.level:
text: Make {0} {1}
comparision.between.object.and.primitive:
text: Comparision between Object and primitive is illegal and is accepted in java 7 only
+conflicting.nullability.annotations:
+ text: Conflicting nullability annotations
contract.return.validator.incompatible.return.parameter.type:
text: return type ''{0}'' must be convertible from parameter type ''{1}''
contract.return.validator.method.return.incompatible.with.method.containing.class:
@@ -686,12 +688,46 @@ inspection.nullable.problems.annotated.field.setter.parameter.conflict:
text: Setter parameter for @{0} field is annotated @{1}
inspection.nullable.problems.annotated.field.setter.parameter.not.annotated:
text: Setter parameter for @{0} field might be annotated @{0} itself
+inspection.nullable.problems.applied.to.package:
+ text: Annotation on fully-qualified name must be placed before the last component
+inspection.nullable.problems.at.class:
+ text: Nullability annotation is not applicable to classes
+inspection.nullable.problems.at.constructor:
+ text: Nullability annotation is not applicable to constructors
+inspection.nullable.problems.at.enum.constant:
+ text: Nullability annotation is not applicable to enum constants
+inspection.nullable.problems.at.local.variable:
+ text: Nullability annotation is not applicable to local variables
+inspection.nullable.problems.at.reference.list:
+ text: Nullability annotation is not applicable to extends/implements clause
+inspection.nullable.problems.at.throws:
+ text: Nullability annotation is not applicable to 'throws' clause
+inspection.nullable.problems.at.type.parameter:
+ text: Nullability annotation is not applicable to type parameters
+inspection.nullable.problems.at.wildcard:
+ text: Nullability annotation is not applicable to wildcard type
+inspection.nullable.problems.constructor.not.compatible.non.null.type.argument:
+ text: Constructor is not compatible with a non-null type argument
inspection.nullable.problems.method.overrides.NotNull:
text: Not annotated method overrides method annotated with @{0}
+inspection.nullable.problems.nullable.instantiation.of.notnull:
+ text: Non-null type parameter ''{0}'' cannot be instantiated with @{1} type
+inspection.nullable.problems.nullable.instantiation.of.notnull.container:
+ text: Non-null type parameter ''{0}'' cannot be instantiated under @{1}
+inspection.nullable.problems.outer.type:
+ text: Outer type is inherently non-null
inspection.nullable.problems.parameter.overrides.NotNull:
text: Not annotated parameter overrides @{0} parameter
inspection.nullable.problems.primitive.type.annotation:
text: Primitive type members cannot be annotated
+inspection.nullable.problems.receiver.annotation:
+ text: Receiver parameter is inherently non-null
+inspection.nullable.problems.redundant.annotation.inherited.notnull:
+ text: 'Redundant nullability annotation: type parameter upper bound is already non-null'
+inspection.nullable.problems.redundant.annotation.under.container:
+ text: Redundant nullability annotation in the scope of @{0}
+inspection.nullable.problems.turn.off.redundant.annotation.under.container:
+ text: Don't report redundant nullability annotation in the scope of annotated container
inspection.numeric.overflow.display.name:
text: Numeric overflow
inspection.objects.equals.can.be.simplified.display.name:
@@ -1068,3 +1104,17 @@ vararg.method.call.with.50.poly.arguments:
text: Vararg method call with 50+ poly arguments may cause compilation and analysis slowdown
visible.for.testing.makes.little.sense.on.test.only.code:
text: '@VisibleForTesting makes little sense on @TestOnly code'
+complex.problem.with.nullability:
+ text:
Incompatible type arguments due to nullability{0}
+assigning.a.class.with.nullable.elements:
+ text: Assigning a class with nullable type arguments when a class with not-null type arguments is expected{0}
+assigning.a.class.with.notnull.elements:
+ text: Assigning a class with not-null type arguments when a class with nullable type arguments is expected{0}
+overriding.a.class.with.nullable.elements:
+ text: Overriding a class with nullable type arguments when a class with not-null type arguments is expected{0}
+overriding.a.class.with.notnull.elements:
+ text: Overriding a class with not-null type arguments when a class with nullable type arguments is expected{0}
+returning.a.class.with.nullable.arguments:
+ text: Returning a class with nullable type arguments when a class with not-null type arguments is expected{0}
+returning.a.class.with.notnull.arguments:
+ text: Returning a class with not-null type arguments when a class with nullable type arguments is expected{0}
diff --git a/java-analysis-impl/src/main/java/com/intellij/java/analysis/impl/codeInspection/nullable/NullableStuffInspectionBase.java b/java-analysis-impl/src/main/java/com/intellij/java/analysis/impl/codeInspection/nullable/NullableStuffInspectionBase.java
index 7171dbbed..1efd8af73 100644
--- a/java-analysis-impl/src/main/java/com/intellij/java/analysis/impl/codeInspection/nullable/NullableStuffInspectionBase.java
+++ b/java-analysis-impl/src/main/java/com/intellij/java/analysis/impl/codeInspection/nullable/NullableStuffInspectionBase.java
@@ -1,7 +1,6 @@
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.java.analysis.impl.codeInspection.nullable;
-import com.intellij.java.analysis.JavaAnalysisBundle;
import com.intellij.java.analysis.codeInspection.AbstractBaseJavaLocalInspectionTool;
import com.intellij.java.analysis.impl.codeInsight.intention.AddAnnotationFix;
import com.intellij.java.analysis.impl.codeInsight.intention.AddAnnotationPsiFix;
@@ -21,7 +20,9 @@
import com.intellij.java.language.psi.util.*;
import com.intellij.java.language.util.JavaTypeNullabilityUtil;
import com.siyeh.ig.psiutils.TypeUtils;
+import consulo.annotation.access.RequiredReadAction;
import consulo.application.util.registry.Registry;
+import consulo.java.analysis.localize.JavaAnalysisLocalize;
import consulo.language.editor.FileModificationService;
import consulo.language.editor.inspection.*;
import consulo.language.editor.inspection.localize.InspectionLocalize;
@@ -33,18 +34,18 @@
import consulo.logging.Logger;
import consulo.project.Project;
import consulo.project.content.GeneratedSourcesFilter;
+import consulo.ui.annotation.RequiredUIAccess;
import consulo.util.collection.ArrayUtil;
import consulo.util.collection.ContainerUtil;
import consulo.util.lang.StringUtil;
import consulo.virtualFileSystem.VirtualFile;
import one.util.streamex.StreamEx;
import org.jetbrains.annotations.Contract;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.PropertyKey;
import org.jspecify.annotations.Nullable;
import java.util.*;
import java.util.function.Consumer;
+import java.util.function.Function;
import java.util.function.Predicate;
import static com.intellij.java.language.codeInsight.AnnotationUtil.*;
@@ -56,10 +57,13 @@ public abstract class NullableStuffInspectionBase extends AbstractBaseJavaLocalI
private static Logger LOG = Logger.getInstance(NullableStuffInspectionBase.class);
@Override
- public PsiElementVisitor buildVisitorImpl(final ProblemsHolder holder,
- final boolean isOnTheFly,
- LocalInspectionToolSession session,
- NullableStuffInspectionState state) {
+ @RequiredReadAction
+ public PsiElementVisitor buildVisitorImpl(
+ final ProblemsHolder holder,
+ final boolean isOnTheFly,
+ LocalInspectionToolSession session,
+ NullableStuffInspectionState state
+ ) {
PsiFile file = holder.getFile();
if (!PsiUtil.isAvailable(JavaFeature.ANNOTATIONS, file) || nullabilityAnnotationsNotAvailable(file)) {
return PsiElementVisitor.EMPTY_VISITOR;
@@ -70,6 +74,7 @@ public PsiElementVisitor buildVisitorImpl(final ProblemsHolder holder,
private List notNulls = manager.getNotNulls();
@Override
+ @RequiredReadAction
public void visitMethod(PsiMethod method) {
checkNullableStuffForMethod(method, holder, state);
}
@@ -96,6 +101,7 @@ public void visitModule(PsiJavaModule module) {
}
@Override
+ @RequiredReadAction
public void visitNewExpression(PsiNewExpression expression) {
if (expression.isArrayCreation()) {
return;
@@ -136,33 +142,40 @@ public void visitNewExpression(PsiNewExpression expression) {
}
AddTypeAnnotationFix fix = null;
- if (classType.getPsiContext() instanceof PsiJavaCodeReferenceElement typeRef &&
- typeRef.getParent() instanceof PsiTypeElement typeElement && typeElement.getType().equals(classType) &&
- typeElement.acceptsAnnotations()) {
+ if (classType.getPsiContext() instanceof PsiJavaCodeReferenceElement typeRef
+ && typeRef.getParent() instanceof PsiTypeElement typeElement
+ && typeElement.getType().equals(classType)
+ && typeElement.acceptsAnnotations()) {
fix = new AddTypeAnnotationFix(typeElement, manager.getDefaultAnnotation(Nullability.NULLABLE, expression), notNulls);
}
- holder.problem(expression,
- JavaAnalysisBundle.message("inspection.nullable.problems.constructor.not.compatible.non.null.type.argument"))
+ holder.problem(
+ expression,
+ JavaAnalysisLocalize.inspectionNullableProblemsConstructorNotCompatibleNonNullTypeArgument()
+ )
.maybeFix(fix)
.register();
}
@Override
+ @RequiredReadAction
public void visitMethodReferenceExpression(PsiMethodReferenceExpression expression) {
checkMethodReference(expression, holder, state);
JavaResolveResult result = expression.advancedResolve(false);
- PsiElement target = result.getElement();
- if (target instanceof PsiMethod) {
- checkNestedGenericClasses(holder, expression,
+ if (result.getElement() instanceof PsiMethod method) {
+ checkNestedGenericClasses(
+ holder,
+ expression,
LambdaUtil.getFunctionalInterfaceReturnType(expression),
- result.getSubstitutor().substitute(((PsiMethod) target).getReturnType()),
+ result.getSubstitutor().substitute(method.getReturnType()),
ConflictNestedTypeProblem.ASSIGNMENT_NESTED_TYPE_PROBLEM,
- state);
+ state
+ );
}
}
@Override
+ @RequiredReadAction
public void visitField(PsiField field) {
PsiType type = field.getType();
Annotated annotated = check(field, holder, type);
@@ -183,11 +196,13 @@ public void visitField(PsiField field) {
PsiElement identifyingElement = field.getIdentifyingElement();
if (initializer != null && identifyingElement != null) {
checkNestedGenericClasses(holder, identifyingElement, field.getType(), initializer.getType(),
- ConflictNestedTypeProblem.ASSIGNMENT_NESTED_TYPE_PROBLEM, state);
+ ConflictNestedTypeProblem.ASSIGNMENT_NESTED_TYPE_PROBLEM, state
+ );
}
}
@Override
+ @RequiredReadAction
public void visitMethodCallExpression(PsiMethodCallExpression call) {
super.visitMethodCallExpression(call);
PsiReferenceParameterList parameterList = call.getMethodExpression().getParameterList();
@@ -222,27 +237,41 @@ public void visitMethodCallExpression(PsiMethodCallExpression call) {
PsiAnnotation anchor = explicit.annotation();
PsiJavaCodeReferenceElement ref = anchor.getNameReferenceElement();
if (ref != null) {
- reportProblem(holder, anchor, "inspection.nullable.problems.nullable.instantiation.of.notnull",
- typeParameter.getName(), ref.getReferenceName());
+ reportProblem(
+ holder,
+ anchor,
+ JavaAnalysisLocalize.inspectionNullableProblemsNullableInstantiationOfNotnull(
+ typeParameter.getName(),
+ ref.getReferenceName()
+ )
+ );
}
}
else if (source instanceof NullabilitySource.ContainerAnnotation container) {
PsiElement anchor = parameterList.getTypeParameterElements()[i];
PsiJavaCodeReferenceElement ref = container.annotation().getNameReferenceElement();
if (ref != null) {
- reportProblem(holder, anchor, "inspection.nullable.problems.nullable.instantiation.of.notnull.container",
- typeParameter.getName(), ref.getReferenceName());
+ reportProblem(
+ holder,
+ anchor,
+ JavaAnalysisLocalize.inspectionNullableProblemsNullableInstantiationOfNotnullContainer(
+ typeParameter.getName(),
+ ref.getReferenceName()
+ )
+ );
}
}
}
}
@Override
+ @RequiredReadAction
public void visitParameter(PsiParameter parameter) {
check(parameter, holder, parameter.getType());
}
@Override
+ @RequiredReadAction
public void visitAnnotation(PsiAnnotation annotation) {
NullabilityAnnotationWrapper wrapper = NullabilityAnnotationWrapper.from(annotation);
if (wrapper == null) {
@@ -252,16 +281,19 @@ public void visitAnnotation(PsiAnnotation annotation) {
PsiType type = wrapper.type();
PsiModifierListOwner listOwner = wrapper.listOwner();
checkRedundantInContainerScope(wrapper, state);
- if (type != null &&
- wrapper.nullability() == Nullability.NOT_NULL &&
- PsiUtil.resolveClassInClassTypeOnly(type) instanceof PsiTypeParameter) {
+ if (type != null
+ && wrapper.nullability() == Nullability.NOT_NULL
+ && PsiUtil.resolveClassInClassTypeOnly(type) instanceof PsiTypeParameter) {
PsiType notAnnotated = type.annotate(TypeAnnotationProvider.EMPTY);
TypeNullability notAnnotatedNullability = notAnnotated.getNullability();
- if (notAnnotatedNullability.nullability() == Nullability.NOT_NULL &&
- notAnnotatedNullability.source() instanceof NullabilitySource.ExtendsBound) {
- reportProblem(holder, annotation,
+ if (notAnnotatedNullability.nullability() == Nullability.NOT_NULL
+ && notAnnotatedNullability.source() instanceof NullabilitySource.ExtendsBound) {
+ reportProblem(
+ holder,
+ annotation,
new RemoveAnnotationQuickFix(annotation, null),
- "inspection.nullable.problems.redundant.annotation.inherited.notnull");
+ JavaAnalysisLocalize.inspectionNullableProblemsRedundantAnnotationInheritedNotnull()
+ );
}
}
if (type instanceof PsiPrimitiveType) {
@@ -269,7 +301,13 @@ public void visitAnnotation(PsiAnnotation annotation) {
if (targetType instanceof PsiArrayType && !targetType.hasAnnotations()) {
additionalFix = new MoveAnnotationToArrayFix();
}
- reportIncorrectLocation(holder, annotation, listOwner, "inspection.nullable.problems.primitive.type.annotation", LocalQuickFix.notNullElements(additionalFix));
+ reportIncorrectLocation(
+ holder,
+ annotation,
+ listOwner,
+ JavaAnalysisLocalize.inspectionNullableProblemsPrimitiveTypeAnnotation(),
+ LocalQuickFix.notNullElements(additionalFix)
+ );
}
if (type instanceof PsiClassType classType) {
PsiElement context = classType.getPsiContext();
@@ -279,56 +317,99 @@ public void visitAnnotation(PsiAnnotation annotation) {
if (parent instanceof PsiJavaCodeReferenceElement) {
if (outerCtx.resolve() instanceof PsiPackage) {
ModCommandAction action = new MoveAnnotationOnStaticMemberQualifyingTypeFix(annotation);
- reportIncorrectLocation(holder, annotation, listOwner, "inspection.nullable.problems.applied.to.package",
- LocalQuickFix.from(action));
+ reportIncorrectLocation(
+ holder,
+ annotation,
+ listOwner,
+ JavaAnalysisLocalize.inspectionNullableProblemsAppliedToPackage(),
+ LocalQuickFix.from(action)
+ );
}
else {
// If outer is qualifier of static member then don't report problem as it is already reported
// as ANNOTATION_NOT_ALLOWED_STATIC which contains exactly the same fix "Move annotation".
if (!PsiImplUtil.isTypeQualifierOfStaticMember(outerCtx)) {
ModCommandAction action = new MoveAnnotationOnStaticMemberQualifyingTypeFix(annotation);
- reportIncorrectLocation(holder, annotation, listOwner, "inspection.nullable.problems.outer.type",
- LocalQuickFix.from(action));
+ reportIncorrectLocation(
+ holder,
+ annotation,
+ listOwner,
+ JavaAnalysisLocalize.inspectionNullableProblemsOuterType(),
+ LocalQuickFix.from(action)
+ );
}
}
}
if (parent instanceof PsiReferenceList) {
PsiElement firstChild = parent.getFirstChild();
if ((PsiUtil.isJavaToken(firstChild, JavaTokenType.EXTENDS_KEYWORD) ||
- PsiUtil.isJavaToken(firstChild, JavaTokenType.IMPLEMENTS_KEYWORD)) &&
- !(parent.getParent() instanceof PsiTypeParameter)) {
- reportIncorrectLocation(holder, annotation, listOwner, "inspection.nullable.problems.at.reference.list");
+ PsiUtil.isJavaToken(firstChild, JavaTokenType.IMPLEMENTS_KEYWORD))
+ && !(parent.getParent() instanceof PsiTypeParameter)) {
+ reportIncorrectLocation(holder, annotation, listOwner, JavaAnalysisLocalize.inspectionNullableProblemsAtReferenceList());
}
if (PsiUtil.isJavaToken(firstChild, JavaTokenType.THROWS_KEYWORD)) {
- reportIncorrectLocation(holder, annotation, listOwner, "inspection.nullable.problems.at.throws");
+ reportIncorrectLocation(holder, annotation, listOwner, JavaAnalysisLocalize.inspectionNullableProblemsAtThrows());
}
}
}
}
- if (type instanceof PsiArrayType && annotation.getParent() instanceof PsiTypeElement parent &&
- parent.getType().equals(type) && !manager.canAnnotateLocals(wrapper.qualifiedName())) {
+ if (type instanceof PsiArrayType
+ && annotation.getParent() instanceof PsiTypeElement parent
+ && parent.getType().equals(type)
+ && !manager.canAnnotateLocals(wrapper.qualifiedName())) {
checkIllegalLocalAnnotation(annotation, parent.getParent(), state);
}
if (listOwner instanceof PsiMethod method && method.isConstructor()) {
- reportIncorrectLocation(holder, annotation, listOwner, "inspection.nullable.problems.at.constructor");
+ reportIncorrectLocation(
+ holder,
+ annotation,
+ listOwner,
+ JavaAnalysisLocalize.inspectionNullableProblemsAtConstructor()
+ );
}
- if (listOwner instanceof PsiClass && AnnotationTargetUtil.findAnnotationTarget(annotation, PsiAnnotation.TargetType.TYPE) == null) {
- reportIncorrectLocation(holder, annotation, listOwner, "inspection.nullable.problems.at.class");
+ if (listOwner instanceof PsiClass
+ && AnnotationTargetUtil.findAnnotationTarget(annotation, PsiAnnotation.TargetType.TYPE) == null) {
+ reportIncorrectLocation(
+ holder,
+ annotation,
+ listOwner,
+ JavaAnalysisLocalize.inspectionNullableProblemsAtClass()
+ );
}
if (listOwner instanceof PsiEnumConstant) {
- reportIncorrectLocation(holder, annotation, listOwner, "inspection.nullable.problems.at.enum.constant");
+ reportIncorrectLocation(
+ holder,
+ annotation,
+ listOwner,
+ JavaAnalysisLocalize.inspectionNullableProblemsAtEnumConstant()
+ );
}
if (!manager.canAnnotateLocals(wrapper.qualifiedName()) && !(targetType instanceof PsiArrayType)) {
checkIllegalLocalAnnotation(annotation, listOwner, state);
}
if (type instanceof PsiWildcardType && manager.isTypeUseAnnotationLocationRestricted(wrapper.qualifiedName())) {
- reportIncorrectLocation(holder, annotation, listOwner, "inspection.nullable.problems.at.wildcard");
+ reportIncorrectLocation(
+ holder,
+ annotation,
+ listOwner,
+ JavaAnalysisLocalize.inspectionNullableProblemsAtWildcard()
+ );
}
if (wrapper.owner() instanceof PsiTypeParameter && manager.isTypeUseAnnotationLocationRestricted(wrapper.qualifiedName())) {
- reportIncorrectLocation(holder, annotation, listOwner, "inspection.nullable.problems.at.type.parameter");
+ reportIncorrectLocation(
+ holder,
+ annotation,
+ listOwner,
+ JavaAnalysisLocalize.inspectionNullableProblemsAtTypeParameter()
+ );
}
if (listOwner instanceof PsiReceiverParameter && wrapper.nullability() != Nullability.NOT_NULL) {
- reportIncorrectLocation(holder, annotation, listOwner, "inspection.nullable.problems.receiver.annotation");
+ reportIncorrectLocation(
+ holder,
+ annotation,
+ listOwner,
+ JavaAnalysisLocalize.inspectionNullableProblemsReceiverAnnotation()
+ );
}
checkOppositeAnnotationConflict(annotation, wrapper.nullability());
if (NOT_NULL.equals(wrapper.qualifiedName())) {
@@ -336,7 +417,7 @@ public void visitAnnotation(PsiAnnotation annotation) {
if (value instanceof PsiClassObjectAccessExpression classObjectAccessExpression) {
PsiClass psiClass = PsiUtil.resolveClassInClassTypeOnly(classObjectAccessExpression.getOperand().getType());
if (psiClass != null && !hasStringConstructor(psiClass)) {
- reportProblem(holder, value, "custom.exception.class.should.have.a.constructor");
+ reportProblem(holder, value, JavaAnalysisLocalize.customExceptionClassShouldHaveAConstructor());
}
}
}
@@ -358,24 +439,37 @@ private void reportRedundantInContainerScope(PsiAnnotation annotation, Nullabili
PsiJavaCodeReferenceElement containerName = containerInfo.getAnnotation().getNameReferenceElement();
if (containerName != null) {
LocalQuickFix updateOptionFix = LocalQuickFix.from(
- new UpdateInspectionOptionFix(NullableStuffInspectionBase.this,
+ new UpdateInspectionOptionFix(
+ NullableStuffInspectionBase.this,
"REPORT_REDUNDANT_NULLABILITY_ANNOTATION_IN_THE_SCOPE_OF_ANNOTATED_CONTAINER",
- JavaAnalysisBundle.message("inspection.nullable.problems.turn.off.redundant.annotation.under.container"),
- false));
- reportProblem(holder, annotation,
+ JavaAnalysisLocalize.inspectionNullableProblemsTurnOffRedundantAnnotationUnderContainer(),
+ false
+ ));
+ reportProblem(holder,
+ annotation,
LocalQuickFix.notNullElements(new RemoveAnnotationQuickFix(annotation, null), updateOptionFix),
- "inspection.nullable.problems.redundant.annotation.under.container", containerName.getReferenceName());
+ JavaAnalysisLocalize.inspectionNullableProblemsRedundantAnnotationUnderContainer(containerName.getReferenceName())
+ );
}
}
- private void checkIllegalLocalAnnotation(PsiAnnotation annotation, @Nullable PsiElement owner, NullableStuffInspectionState state) {
+ private void checkIllegalLocalAnnotation(
+ PsiAnnotation annotation,
+ @Nullable PsiElement owner,
+ NullableStuffInspectionState state
+ ) {
if (!state.REPORT_NULLABILITY_ANNOTATION_ON_LOCALS) {
return;
}
if (owner instanceof PsiLocalVariable ||
- owner instanceof PsiParameter parameter &&
- parameter.getDeclarationScope() instanceof PsiCatchSection) {
- reportIncorrectLocation(holder, annotation, (PsiVariable) owner, "inspection.nullable.problems.at.local.variable");
+ owner instanceof PsiParameter parameter
+ && parameter.getDeclarationScope() instanceof PsiCatchSection) {
+ reportIncorrectLocation(
+ holder,
+ annotation,
+ (PsiVariable) owner,
+ JavaAnalysisLocalize.inspectionNullableProblemsAtLocalVariable()
+ );
}
}
@@ -388,7 +482,9 @@ private void checkOppositeAnnotationConflict(PsiAnnotation annotation, Nullabili
? tryCast(modifierList.getParent(), PsiModifierListOwner.class)
: null;
Predicate filter = anno ->
- anno != annotation && manager.getAnnotationNullability(anno.getQualifiedName()).filter(n -> n != nullability).isPresent();
+ anno != annotation && manager.getAnnotationNullability(anno.getQualifiedName())
+ .filter(n -> n != nullability)
+ .isPresent();
PsiAnnotation oppositeAnno = ContainerUtil.find(owner.getAnnotations(), filter);
if (oppositeAnno == null && listOwner != null) {
NullabilityAnnotationInfo result = manager.findNullabilityAnnotationInfo(
@@ -397,9 +493,15 @@ private void checkOppositeAnnotationConflict(PsiAnnotation annotation, Nullabili
}
if (oppositeAnno != null &&
Objects.equals(getRelatedType(annotation), getRelatedType(oppositeAnno))) {
- reportProblem(holder, annotation, new RemoveAnnotationQuickFix(annotation, listOwner),
- "inspection.nullable.problems.Nullable.NotNull.conflict",
- getPresentableAnnoName(annotation), getPresentableAnnoName(oppositeAnno));
+ reportProblem(
+ holder,
+ annotation,
+ new RemoveAnnotationQuickFix(annotation, listOwner),
+ JavaAnalysisLocalize.inspectionNullableProblemsNullableNotnullConflict(
+ getPresentableAnnoName(annotation),
+ getPresentableAnnoName(oppositeAnno)
+ )
+ );
}
}
@@ -415,6 +517,7 @@ private static boolean hasStringConstructor(PsiClass aClass) {
}
@Override
+ @RequiredReadAction
public void visitReferenceElement(PsiJavaCodeReferenceElement reference) {
super.visitReferenceElement(reference);
@@ -422,24 +525,28 @@ public void visitReferenceElement(PsiJavaCodeReferenceElement reference) {
PsiElement list = reference.getParent();
PsiElement parent = list instanceof PsiReferenceList ? list.getParent() : null;
- if (parent instanceof PsiClass psiClass && list == psiClass.getImplementsList() &&
- reference.resolve() instanceof PsiClass intf && intf.isInterface()) {
- String error = checkIndirectInheritance(psiClass, intf);
- if (error != null) {
- holder.registerProblem(reference, error);
+ if (parent instanceof PsiClass psiClass
+ && list == psiClass.getImplementsList()
+ && reference.resolve() instanceof PsiClass intf
+ && intf.isInterface()) {
+ LocalizeValue error = checkIndirectInheritance(psiClass, intf);
+ if (error.isNotEmpty()) {
+ holder.newProblem(error)
+ .range(reference)
+ .create();
}
}
}
+ @RequiredReadAction
private void checkNullableNotNullInstantiationConflict(PsiJavaCodeReferenceElement reference) {
- PsiElement element = reference.resolve();
- if (element instanceof PsiClass) {
- PsiTypeParameter[] typeParameters = ((PsiClass) element).getTypeParameters();
+ if (reference.resolve() instanceof PsiClass psiClass) {
+ PsiTypeParameter[] typeParameters = psiClass.getTypeParameters();
PsiTypeElement[] typeArguments = getReferenceTypeArguments(reference);
if (typeParameters.length > 0 && typeParameters.length == typeArguments.length && !(typeArguments[0].getType() instanceof PsiDiamondType)) {
for (int i = 0; i < typeParameters.length; i++) {
PsiTypeElement typeArgument = typeArguments[i];
- Project project = element.getProject();
+ Project project = psiClass.getProject();
PsiType type = typeArgument.getType();
if (TypeNullability.ofTypeParameter(typeParameters[i]).nullability() != Nullability.NOT_NULL) {
continue;
@@ -449,24 +556,30 @@ private void checkNullableNotNullInstantiationConflict(PsiJavaCodeReferenceEleme
if (typeNullability != Nullability.NOT_NULL &&
!(typeNullability == Nullability.UNKNOWN && type instanceof PsiWildcardType wildcardType && !wildcardType.isExtends())) {
String annotationToAdd = manager.getDefaultAnnotation(Nullability.NOT_NULL, reference);
- PsiClass annotationClass = JavaPsiFacade.getInstance(project).findClass(annotationToAdd, element.getResolveScope());
+ PsiClass annotationClass =
+ JavaPsiFacade.getInstance(project).findClass(annotationToAdd, psiClass.getResolveScope());
List fixes = new ArrayList<>();
if (annotationClass != null &&
AnnotationTargetUtil.findAnnotationTarget(annotationClass, PsiAnnotation.TargetType.TYPE_USE) != null) {
- fixes.add(LocalQuickFix.from(new AddTypeAnnotationFix(typeArgument, annotationToAdd, manager.getNullables())));
+ fixes.add(LocalQuickFix.from(new AddTypeAnnotationFix(
+ typeArgument,
+ annotationToAdd,
+ manager.getNullables()
+ )));
}
fixes.add(LocalQuickFix.from(createAnnotateAsNullMarkedFix(typeArgument, manager.getNullables())));
ProblemHighlightType level =
- nullability == TypeNullability.UNKNOWN && !state.REPORT_NOT_ANNOTATED_INSTANTIATION_NOT_NULL_TYPE ?
- ProblemHighlightType.INFORMATION :
- ProblemHighlightType.GENERIC_ERROR_OR_WARNING;
+ nullability == TypeNullability.UNKNOWN && !state.REPORT_NOT_ANNOTATED_INSTANTIATION_NOT_NULL_TYPE
+ ? ProblemHighlightType.INFORMATION
+ : ProblemHighlightType.GENERIC_ERROR_OR_WARNING;
if (!isOnTheFly && level == ProblemHighlightType.INFORMATION) {
continue;
}
- holder.registerProblem(typeArgument,
- JavaAnalysisBundle.message("non.null.type.argument.is.expected"),
- level,
- fixes.toArray(LocalQuickFix.EMPTY_ARRAY));
+ holder.newProblem(JavaAnalysisLocalize.nonNullTypeArgumentIsExpected())
+ .range(typeArgument)
+ .withFixes(fixes)
+ .highlightType(level)
+ .create();
}
}
}
@@ -487,7 +600,8 @@ public void visitAssignmentExpression(PsiAssignmentExpression expression) {
checkNestedGenericClasses(holder, expression.getOperationSign(),
expression.getLExpression().getType(),
rExpression.getType(),
- ConflictNestedTypeProblem.ASSIGNMENT_NESTED_TYPE_PROBLEM, state);
+ ConflictNestedTypeProblem.ASSIGNMENT_NESTED_TYPE_PROBLEM, state
+ );
}
@Override
@@ -501,7 +615,8 @@ public void visitLocalVariable(PsiLocalVariable variable) {
return;
}
checkNestedGenericClasses(holder, identifier, variable.getType(), initializer.getType(),
- ConflictNestedTypeProblem.ASSIGNMENT_NESTED_TYPE_PROBLEM, state);
+ ConflictNestedTypeProblem.ASSIGNMENT_NESTED_TYPE_PROBLEM, state
+ );
}
@Override
@@ -512,7 +627,8 @@ public void visitReturnStatement(PsiReturnStatement statement) {
}
checkNestedGenericClasses(holder, returnValue,
PsiTypesUtil.getMethodReturnType(statement), returnValue.getType(),
- ConflictNestedTypeProblem.RETURN_NESTED_TYPE_PROBLEM, state);
+ ConflictNestedTypeProblem.RETURN_NESTED_TYPE_PROBLEM, state
+ );
}
@Override
@@ -520,7 +636,8 @@ public void visitLambdaExpression(PsiLambdaExpression lambda) {
super.visitLambdaExpression(lambda);
PsiElement body = lambda.getBody();
if (body instanceof PsiExpression psiExpression) {
- checkNestedGenericClasses(holder,
+ checkNestedGenericClasses(
+ holder,
body,
LambdaUtil.getFunctionalInterfaceReturnType(lambda),
psiExpression.getType(),
@@ -548,40 +665,49 @@ public void visitCallExpression(PsiCallExpression callExpression) {
(i < parameters.length - 1 || !MethodCallInstruction.isVarArgCall(method, substitutor, arguments, parameters))) {
PsiType expectedType = substitutor.substitute(parameters[i].getType());
checkNestedGenericClasses(holder, argument, expectedType, argument.getType(),
- ConflictNestedTypeProblem.ASSIGNMENT_NESTED_TYPE_PROBLEM, state);
+ ConflictNestedTypeProblem.ASSIGNMENT_NESTED_TYPE_PROBLEM, state
+ );
}
}
}
};
}
- private boolean checkNestedGenericClasses(ProblemsHolder holder,
- PsiElement errorElement,
- @Nullable PsiType expectedType,
- @Nullable PsiType actualType,
- ConflictNestedTypeProblem problem,
- NullableStuffInspectionState state) {
+ private boolean checkNestedGenericClasses(
+ ProblemsHolder holder,
+ PsiElement errorElement,
+ @Nullable PsiType expectedType,
+ @Nullable PsiType actualType,
+ ConflictNestedTypeProblem problem,
+ NullableStuffInspectionState state
+ ) {
if (expectedType == null || actualType == null) {
return false;
}
- JavaTypeNullabilityUtil.NullabilityConflictContext
- context = JavaTypeNullabilityUtil.getNullabilityConflictInAssignment(expectedType, actualType,
- state.REPORT_NOT_NULL_TO_NULLABLE_CONFLICTS_IN_ASSIGNMENTS);
+ JavaTypeNullabilityUtil.NullabilityConflictContext context = JavaTypeNullabilityUtil.getNullabilityConflictInAssignment(
+ expectedType,
+ actualType,
+ state.REPORT_NOT_NULL_TO_NULLABLE_CONFLICTS_IN_ASSIGNMENTS
+ );
JavaTypeNullabilityUtil.NullabilityConflict conflict = context.nullabilityConflict();
- String messageKey = switch (conflict) {
- case UNKNOWN -> null;
- case NOT_NULL_TO_NULL -> problem.notNullToNullProblem();
- case NULL_TO_NOT_NULL -> problem.nullToNotNullProblem();
- case COMPLEX -> problem.complexProblem();
- };
- if (messageKey == null) {
+ if (conflict == JavaTypeNullabilityUtil.NullabilityConflict.UNKNOWN) {
return false;
}
- reportProblem(holder, errorElement, LocalQuickFix.EMPTY_ARRAY,
- messageKey, new Object[]{""},
- messageKey, new Object[]{NullableStuffInspectionUtil.getNullabilityConflictPresentation(context)});
+ Function