From b19ff01e910156bfc14eed6153672e95e989c750 Mon Sep 17 00:00:00 2001 From: Tagir Valeev Date: Mon, 3 Nov 2025 11:25:01 +0100 Subject: [PATCH] [java-inspections] IDEA-381329 IDEA provides the warning for code even if JSpecify added transitively and code in project is not marked. (cherry picked from commit 2454b9d89a12c4c5afabb370b84ac17362b56ccc) Review ID: IJ-CR-181202 GitOrigin-RevId: 76016e9c1dc4c1064357ffca1005e60841b6e3d9 --- .../nullable/NullableStuffInspectionBase.java | 17 ++++++++++++++--- .../nullable/NullableStuffInspection.java | 1 + ...atedInstantiationOfNonNullTypeParameter.java | 17 +++++++++++++++++ ...edInstantiationOfNonNullTypeParameterOn.java | 17 +++++++++++++++++ .../NullableStuffInspectionTest.java | 15 +++++++++++++++ .../resources/messages/JavaBundle.properties | 1 + 6 files changed, 65 insertions(+), 3 deletions(-) create mode 100644 java/java-tests/testData/inspection/nullableProblems/UnannotatedInstantiationOfNonNullTypeParameter.java create mode 100644 java/java-tests/testData/inspection/nullableProblems/UnannotatedInstantiationOfNonNullTypeParameterOn.java diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/nullable/NullableStuffInspectionBase.java b/java/java-analysis-impl/src/com/intellij/codeInspection/nullable/NullableStuffInspectionBase.java index 36fef291ea65..da74b5b55e16 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/nullable/NullableStuffInspectionBase.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/nullable/NullableStuffInspectionBase.java @@ -69,6 +69,7 @@ public class NullableStuffInspectionBase extends AbstractBaseJavaLocalInspection @SuppressWarnings("WeakerAccess") public boolean IGNORE_EXTERNAL_SUPER_NOTNULL; @SuppressWarnings("WeakerAccess") public boolean REPORT_NOTNULL_PARAMETERS_OVERRIDES_NOT_ANNOTATED; @SuppressWarnings("WeakerAccess") public boolean REPORT_NULLABILITY_ANNOTATION_ON_LOCALS = true; + @SuppressWarnings("WeakerAccess") public boolean REPORT_NOT_ANNOTATED_INSTANTIATION_NOT_NULL_TYPE = false; @SuppressWarnings("WeakerAccess") public boolean REPORT_NOT_NULL_TO_NULLABLE_CONFLICTS_IN_ASSIGNMENTS = false; /** * @deprecated the field remains to minimize changes to users' inspection profiles. @@ -97,7 +98,8 @@ public class NullableStuffInspectionBase extends AbstractBaseJavaLocalInspection "REQUIRE_NOTNULL_FIELDS_INITIALIZED".equals(name) && "true".equals(value) || "REPORT_NULLABILITY_ANNOTATION_ON_LOCALS".equals(name) && "true".equals(value) || "REPORT_NULLS_PASSED_TO_NOT_NULL_PARAMETER".equals(name) && "true".equals(value) || - "REPORT_NOT_NULL_TO_NULLABLE_CONFLICTS_IN_ASSIGNMENTS".equals(name) && "false".equals(value)) { + "REPORT_NOT_NULL_TO_NULLABLE_CONFLICTS_IN_ASSIGNMENTS".equals(name) && "false".equals(value) || + "REPORT_NOT_ANNOTATED_INSTANTIATION_NOT_NULL_TYPE".equals(name) && "false".equals(value)) { node.removeContent(child); } } @@ -438,7 +440,8 @@ public class NullableStuffInspectionBase extends AbstractBaseJavaLocalInspection Project project = element.getProject(); PsiType type = typeArgument.getType(); if (TypeNullability.ofTypeParameter(typeParameters[i]).nullability() != Nullability.NOT_NULL) continue; - Nullability typeNullability = DfaPsiUtil.getTypeNullability(type); + TypeNullability nullability = type.getNullability(); + Nullability typeNullability = nullability.nullability(); if (typeNullability != Nullability.NOT_NULL && !(typeNullability == Nullability.UNKNOWN && type instanceof PsiWildcardType wildcardType && !wildcardType.isExtends())) { String annotationToAdd = manager.getDefaultAnnotation(Nullability.NOT_NULL, reference); @@ -449,7 +452,15 @@ public class NullableStuffInspectionBase extends AbstractBaseJavaLocalInspection fixes.add(LocalQuickFix.from(new AddTypeAnnotationFix(typeArgument, annotationToAdd, manager.getNullables()))); } fixes.add(LocalQuickFix.from(createAnnotateAsNullMarkedFix(typeArgument, manager.getNullables()), false)); - reportProblem(holder, typeArgument, fixes.toArray(LocalQuickFix.EMPTY_ARRAY), "non.null.type.argument.is.expected"); + ProblemHighlightType level = + nullability == TypeNullability.UNKNOWN && !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)); } } } diff --git a/java/java-impl/src/com/intellij/codeInspection/nullable/NullableStuffInspection.java b/java/java-impl/src/com/intellij/codeInspection/nullable/NullableStuffInspection.java index a72052d74bf1..10be542f2809 100644 --- a/java/java-impl/src/com/intellij/codeInspection/nullable/NullableStuffInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/nullable/NullableStuffInspection.java @@ -41,6 +41,7 @@ public class NullableStuffInspection extends NullableStuffInspectionBase { checkbox("REPORT_NOTNULL_PARAMETER_OVERRIDES_NULLABLE", JavaBundle.message("inspection.nullable.problems.method.overrides.notnull.option")), checkbox("REPORT_NOT_ANNOTATED_METHOD_OVERRIDES_NOTNULL", JavaBundle.message("inspection.nullable.problems.method.overrides.option"), checkbox("IGNORE_EXTERNAL_SUPER_NOTNULL", JavaBundle.message("inspection.nullable.problems.ignore.external.notnull"))), + checkbox("REPORT_NOT_ANNOTATED_INSTANTIATION_NOT_NULL_TYPE", JavaBundle.message("inspection.nullable.problems.method.non.annotated.type.argument.option")), checkbox("REPORT_NOTNULL_PARAMETERS_OVERRIDES_NOT_ANNOTATED", JavaBundle.message("inspection.nullable.problems.notnull.overrides.option")), checkbox("REPORT_NOT_ANNOTATED_GETTER", JavaBundle.message("inspection.nullable.problems.not.annotated.getters.for.annotated.fields")), checkbox("REPORT_NULLS_PASSED_TO_NOT_NULL_PARAMETER", JavaBundle.message("inspection.nullable.problems.notnull.parameters.with.null.literal.option")), diff --git a/java/java-tests/testData/inspection/nullableProblems/UnannotatedInstantiationOfNonNullTypeParameter.java b/java/java-tests/testData/inspection/nullableProblems/UnannotatedInstantiationOfNonNullTypeParameter.java new file mode 100644 index 000000000000..20e49e7dcc25 --- /dev/null +++ b/java/java-tests/testData/inspection/nullableProblems/UnannotatedInstantiationOfNonNullTypeParameter.java @@ -0,0 +1,17 @@ +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; + +@NullMarked +class Main { +} + +class Use extends Main { + void test(Main main) { + + } + + void testNullable(Main<@Nullable Integer> nullable) { + + } + +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/nullableProblems/UnannotatedInstantiationOfNonNullTypeParameterOn.java b/java/java-tests/testData/inspection/nullableProblems/UnannotatedInstantiationOfNonNullTypeParameterOn.java new file mode 100644 index 000000000000..7cb1b5a74f93 --- /dev/null +++ b/java/java-tests/testData/inspection/nullableProblems/UnannotatedInstantiationOfNonNullTypeParameterOn.java @@ -0,0 +1,17 @@ +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; + +@NullMarked +class Main { +} + +class Use extends Main<Double> { + void test(Main<String> main) { + + } + + void testNullable(Main<@Nullable Integer> nullable) { + + } + +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/java/codeInspection/NullableStuffInspectionTest.java b/java/java-tests/testSrc/com/intellij/java/codeInspection/NullableStuffInspectionTest.java index 1039f465094f..a37560a866f3 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInspection/NullableStuffInspectionTest.java +++ b/java/java-tests/testSrc/com/intellij/java/codeInspection/NullableStuffInspectionTest.java @@ -298,10 +298,24 @@ public class NullableStuffInspectionTest extends LightJavaCodeInsightFixtureTest } public void testNotNullTypeArgumentWithNullableSuperType() { + myInspection.REPORT_NOT_ANNOTATED_INSTANTIATION_NOT_NULL_TYPE = true; setupTypeUseAnnotations("typeUse", myFixture); doTest(); } + public void testUnannotatedInstantiationOfNonNullTypeParameter() { + addJSpecifyNullMarked(myFixture); + setupTypeUseAnnotations("org.jspecify.annotations", myFixture); + doTest(); + } + + public void testUnannotatedInstantiationOfNonNullTypeParameterOn() { + myInspection.REPORT_NOT_ANNOTATED_INSTANTIATION_NOT_NULL_TYPE = true; + addJSpecifyNullMarked(myFixture); + setupTypeUseAnnotations("org.jspecify.annotations", myFixture); + doTest(); + } + public void testNullableTypeArgumentSOE() { setupTypeUseAnnotations("typeUse", myFixture); doTest(); @@ -383,6 +397,7 @@ public class NullableStuffInspectionTest extends LightJavaCodeInsightFixtureTest } public void testQuickFixOnTypeArgument() { + myInspection.REPORT_NOT_ANNOTATED_INSTANTIATION_NOT_NULL_TYPE = true; setupTypeUseAnnotations("typeUse", myFixture); doTestWithFix("Annotate as '@NotNull'"); } diff --git a/java/openapi/resources/messages/JavaBundle.properties b/java/openapi/resources/messages/JavaBundle.properties index c3944c260325..4a2af79de01c 100644 --- a/java/openapi/resources/messages/JavaBundle.properties +++ b/java/openapi/resources/messages/JavaBundle.properties @@ -557,6 +557,7 @@ inspection.nullable.problems.ignore.external.notnull=&Ignore external @NotNull inspection.nullable.problems.method.overrides.notnull.option=Report @NotNull ¶meters overriding @Nullable and vice versa inspection.nullable.problems.method.overrides.option=Report non-&annotated parameters or methods overriding @NotNull inspection.nullable.problems.not.annotated.getters.for.annotated.fields=Report non-annotated &setter parameters or getters of annotated fields +inspection.nullable.problems.method.non.annotated.type.argument.option=Report non-&annotated type arguments instantiating non-null type parameter inspection.nullable.problems.notnull.overrides.option=Report @NotNull ¶meters overriding non-annotated inspection.nullable.problems.notnull.parameters.with.null.literal.option=Report @NotNull parameters with null-literal argument usages inspection.nullable.problems.nullability.on.locals=Report nullability annotations on local variables when they are non-applicable