diff --git a/java/java-analysis-api/resources/messages/JavaAnalysisBundle.properties b/java/java-analysis-api/resources/messages/JavaAnalysisBundle.properties
index ced422a7d541..24d3395bf715 100644
--- a/java/java-analysis-api/resources/messages/JavaAnalysisBundle.properties
+++ b/java/java-analysis-api/resources/messages/JavaAnalysisBundle.properties
@@ -240,6 +240,7 @@ inspection.nullable.problems.annotated.field.setter.parameter.not.annotated=Sett
inspection.nullable.problems.method.overrides.NotNull=Not annotated method overrides method annotated with @{0}
inspection.nullable.problems.parameter.overrides.NotNull=Not annotated parameter overrides @{0} parameter
inspection.nullable.problems.primitive.type.annotation=Primitive type members cannot be annotated
+inspection.nullable.problems.redundant.annotation.under.container=Redundant nullability annotation in the scope of @{0}
inspection.nullable.problems.receiver.annotation=Receiver parameter is inherently not-null
inspection.nullable.problems.applied.to.package=Annotation on fully-qualified name must be placed before the last component
inspection.nullable.problems.outer.type=Outer type is inherently not-null
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 6ed218f5c493..cb8f45c6de34 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
@@ -210,6 +210,12 @@ public class NullableStuffInspectionBase extends AbstractBaseJavaLocalInspection
? tryCast(modifierList.getParent(), PsiModifierListOwner.class) : null;
PsiType targetType = listOwner instanceof PsiMethod method ? method.getReturnType() :
listOwner instanceof PsiVariable variable ? variable.getType() : null;
+ if (listOwner != null && targetType != null) {
+ checkRedundantInContainerScope(annotation, manager.findContainerAnnotation(listOwner), nullability);
+ }
+ else if (type != null) {
+ checkRedundantInContainerScope(annotation, manager.findDefaultTypeUseNullability(annotation), nullability);
+ }
if (type instanceof PsiPrimitiveType) {
LocalQuickFix additionalFix = null;
if (targetType instanceof PsiArrayType && targetType.getAnnotations().length == 0) {
@@ -281,6 +287,19 @@ public class NullableStuffInspectionBase extends AbstractBaseJavaLocalInspection
}
}
+ private void checkRedundantInContainerScope(@NotNull PsiAnnotation annotation,
+ @Nullable NullabilityAnnotationInfo containerInfo,
+ @NotNull Nullability nullability) {
+ if (containerInfo != null && !containerInfo.getAnnotation().equals(annotation) && containerInfo.getNullability() == nullability) {
+ PsiJavaCodeReferenceElement containerName = containerInfo.getAnnotation().getNameReferenceElement();
+ if (containerName != null) {
+ reportProblem(holder, annotation,
+ new RemoveAnnotationQuickFix(annotation, null),
+ "inspection.nullable.problems.redundant.annotation.under.container", containerName.getReferenceName());
+ }
+ }
+ }
+
private void checkIllegalLocalAnnotation(@NotNull PsiAnnotation annotation, @Nullable PsiElement owner) {
if (owner instanceof PsiLocalVariable ||
owner instanceof PsiParameter parameter &&
diff --git a/java/java-tests/testData/inspection/nullableProblems/RedundantNotNull.java b/java/java-tests/testData/inspection/nullableProblems/RedundantNotNull.java
new file mode 100644
index 000000000000..1568e4baa281
--- /dev/null
+++ b/java/java-tests/testData/inspection/nullableProblems/RedundantNotNull.java
@@ -0,0 +1,17 @@
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jetbrains.annotations.NotNullByDefault;
+import java.util.List;
+
+@NotNullByDefault
+class FromDemo {
+ @NotNull String m(@NotNull String s, @Nullable String s2) {
+ return "";
+ }
+
+ @NotNull String f;
+
+ List<@NotNull String> param(@NotNull String @NotNull [] @NotNull [] a) {
+ return List.of();
+ }
+}
\ 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 193b3349b17d..e999edb9175c 100644
--- a/java/java-tests/testSrc/com/intellij/java/codeInspection/NullableStuffInspectionTest.java
+++ b/java/java-tests/testSrc/com/intellij/java/codeInspection/NullableStuffInspectionTest.java
@@ -443,6 +443,11 @@ public class NullableStuffInspectionTest extends LightJavaCodeInsightFixtureTest
doTest();
}
+ public void testRedundantNotNull() {
+ DataFlowInspectionTestCase.addJetBrainsNotNullByDefault(myFixture);
+ doTest();
+ }
+
public void testNoNotNullWarningIfIndirectSuperMethodIsAnnotated() {
myInspection.REPORT_ANNOTATION_NOT_PROPAGATED_TO_OVERRIDERS = true;
myInspection.REPORT_NOTNULL_PARAMETERS_OVERRIDES_NOT_ANNOTATED = true;