[java-inspections] IDEA-381329 IDEA provides the warning for code even if JSpecify added transitively and code in project is not marked.

GitOrigin-RevId: 2454b9d89a12c4c5afabb370b84ac17362b56ccc
This commit is contained in:
Tagir Valeev
2025-11-03 17:18:12 +00:00
committed by intellij-monorepo-bot
parent a46815e535
commit d2d8283a2a
6 changed files with 64 additions and 2 deletions
@@ -70,6 +70,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.
@@ -100,6 +101,7 @@ public class NullableStuffInspectionBase extends AbstractBaseJavaLocalInspection
"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_ANNOTATED_INSTANTIATION_NOT_NULL_TYPE".equals(name) && "false".equals(value) ||
"REPORT_REDUNDANT_NULLABILITY_ANNOTATION_IN_THE_SCOPE_OF_ANNOTATED_CONTAINER".equals(name) && "true".equals(value)) {
node.removeContent(child);
}
@@ -447,7 +449,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);
@@ -458,7 +461,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));
}
}
}
@@ -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")),
@@ -0,0 +1,17 @@
import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.Nullable;
@NullMarked
class Main<T> {
}
class Use extends Main<Double> {
void test(Main<String> main) {
}
void testNullable(Main<<warning descr="Non-null type argument is expected">@Nullable Integer</warning>> nullable) {
}
}
@@ -0,0 +1,17 @@
import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.Nullable;
@NullMarked
class Main<T> {
}
class Use extends Main<<warning descr="Non-null type argument is expected">Double</warning>> {
void test(Main<<warning descr="Non-null type argument is expected">String</warning>> main) {
}
void testNullable(Main<<warning descr="Non-null type argument is expected">@Nullable Integer</warning>> nullable) {
}
}
@@ -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'");
}
@@ -557,6 +557,7 @@ inspection.nullable.problems.display.name=@NotNull/@Nullable problems
inspection.nullable.problems.ignore.external.notnull=&Ignore external @NotNull
inspection.nullable.problems.method.overrides.notnull.option=Report @NotNull &parameters overriding @Nullable and vice versa
inspection.nullable.problems.method.overrides.option=Report non-&annotated parameters or methods overriding @NotNull
inspection.nullable.problems.method.non.annotated.type.argument.option=Report non-&annotated type arguments instantiating non-null type parameter
inspection.nullable.problems.not.annotated.getters.for.annotated.fields=Report non-annotated &setter/constructor parameters or getters of annotated fields
inspection.nullable.problems.notnull.overrides.option=Report @NotNull &parameters overriding non-annotated
inspection.nullable.problems.notnull.parameters.with.null.literal.option=Report @NotNull parameters with null-literal argument usages