diff --git a/java/java-impl/src/com/intellij/codeInsight/annoPackages/Jsr305Support.java b/java/java-impl/src/com/intellij/codeInsight/annoPackages/Jsr305Support.java index 061b6d1b1422..7c5f9b5f537d 100644 --- a/java/java-impl/src/com/intellij/codeInsight/annoPackages/Jsr305Support.java +++ b/java/java-impl/src/com/intellij/codeInsight/annoPackages/Jsr305Support.java @@ -16,6 +16,7 @@ import java.util.Set; public final class Jsr305Support implements AnnotationPackageSupport { public static final String JAVAX_ANNOTATION_NULLABLE = "javax.annotation.Nullable"; public static final String JAVAX_ANNOTATION_NONNULL = "javax.annotation.Nonnull"; + public static final String JAVAX_ANNOTATION_CHECK_FOR_NULL = "javax.annotation.CheckForNull"; public static final String TYPE_QUALIFIER_NICKNAME = "javax.annotation.meta.TypeQualifierNickname"; @Override @@ -69,10 +70,18 @@ public final class Jsr305Support implements AnnotationPackageSupport { * @return nicknamed nullability declared by this annotation; null if this annotation is not a nullability nickname annotation */ public static @Nullable Nullability getNickNamedNullability(@NotNull PsiClass psiClass) { - if (AnnotationUtil.findAnnotation(psiClass, TYPE_QUALIFIER_NICKNAME) == null) return null; + PsiModifierList modifierList = psiClass.getModifierList(); + if (modifierList == null) return null; + if (!modifierList.hasAnnotation(TYPE_QUALIFIER_NICKNAME)) return null; - PsiAnnotation nonNull = AnnotationUtil.findAnnotation(psiClass, JAVAX_ANNOTATION_NONNULL); - return nonNull != null ? extractNullityFromWhenValue(nonNull) : null; + PsiAnnotation nonNull = modifierList.findAnnotation(JAVAX_ANNOTATION_NONNULL); + if (nonNull != null) { + return extractNullityFromWhenValue(nonNull); + } + if (modifierList.hasAnnotation(JAVAX_ANNOTATION_CHECK_FOR_NULL)) { + return Nullability.NULLABLE; + } + return null; } public static @Nullable Nullability extractNullityFromWhenValue(@NotNull PsiAnnotation nonNull) { @@ -101,7 +110,7 @@ public final class Jsr305Support implements AnnotationPackageSupport { public @NotNull List getNullabilityAnnotations(@NotNull Nullability nullability) { return switch (nullability) { case NOT_NULL -> Collections.singletonList(JAVAX_ANNOTATION_NONNULL); - case NULLABLE -> Arrays.asList(JAVAX_ANNOTATION_NULLABLE, "javax.annotation.CheckForNull"); + case NULLABLE -> Arrays.asList(JAVAX_ANNOTATION_NULLABLE, JAVAX_ANNOTATION_CHECK_FOR_NULL); case UNKNOWN -> Collections.emptyList(); }; } diff --git a/java/java-tests/testData/inspection/dataFlow/fixture/Jsr305CheckForNullAsQualifierNickname.java b/java/java-tests/testData/inspection/dataFlow/fixture/Jsr305CheckForNullAsQualifierNickname.java new file mode 100644 index 000000000000..4fa5e68c1a53 --- /dev/null +++ b/java/java-tests/testData/inspection/dataFlow/fixture/Jsr305CheckForNullAsQualifierNickname.java @@ -0,0 +1,27 @@ +import static javax.annotation.meta.When.MAYBE; + +import javax.annotation.CheckForNull; +import javax.annotation.Nonnull; +import javax.annotation.meta.TypeQualifierNickname; + +class Main { + int go(Lib lib) { + return lib.usingNonnullMaybe().hashCode() + lib.usingCheckForNull().hashCode(); + } + + interface Lib { + @UsingNonnullMaybe + Object usingNonnullMaybe(); + + @UsingCheckForNull + Object usingCheckForNull(); + } + + @Nonnull(when = MAYBE) + @TypeQualifierNickname + @interface UsingNonnullMaybe {} + + @CheckForNull + @TypeQualifierNickname + @interface UsingCheckForNull {} +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/java/codeInspection/DataFlowInspectionTest.java b/java/java-tests/testSrc/com/intellij/java/codeInspection/DataFlowInspectionTest.java index 08588cdd6135..defbd4f08f0e 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInspection/DataFlowInspectionTest.java +++ b/java/java-tests/testSrc/com/intellij/java/codeInspection/DataFlowInspectionTest.java @@ -352,6 +352,12 @@ public class DataFlowInspectionTest extends DataFlowInspectionTestCase { doTest(); } + + public void testJsr305CheckForNullAsQualifierNickname() { + addJavaxNullabilityAnnotations(myFixture); + addJavaxDefaultNullabilityAnnotations(myFixture); + doTest(); + } public void testNullabilityDefaultVsMethodImplementing() { addJavaxDefaultNullabilityAnnotations(myFixture); @@ -396,16 +402,24 @@ public class DataFlowInspectionTest extends DataFlowInspectionTestCase { fixture.addClass("package javax.annotation.meta;" + "public enum When { ALWAYS, UNKNOWN, MAYBE, NEVER }"); - fixture.addClass("package javax.annotation;" + - "import javax.annotation.meta.*;" + - "public @interface Nonnull {" + - " When when() default When.ALWAYS;" + - "}"); - fixture.addClass("package javax.annotation;" + - "import javax.annotation.meta.*;" + - "@TypeQualifierNickname " + - "@Nonnull(when = When.UNKNOWN) " + - "public @interface Nullable {}"); + fixture.addClass(""" + package javax.annotation; + import javax.annotation.meta.*; + public @interface Nonnull { + When when() default When.ALWAYS; + }"""); + fixture.addClass(""" + package javax.annotation; + import javax.annotation.meta.*; + @TypeQualifierNickname + @Nonnull(when = When.MAYBE) + public @interface CheckForNull {}"""); + fixture.addClass(""" + package javax.annotation; + import javax.annotation.meta.*; + @TypeQualifierNickname + @Nonnull(when = When.UNKNOWN) + public @interface Nullable {}"""); } public void testCustomTypeQualifierDefault() {