diff --git a/java/java-analysis-impl/src/com/siyeh/ig/style/TypeParameterExtendsObjectInspection.java b/java/java-analysis-impl/src/com/siyeh/ig/style/TypeParameterExtendsObjectInspection.java
index b10bcf2b0a4e..18c9c9fb5d92 100644
--- a/java/java-analysis-impl/src/com/siyeh/ig/style/TypeParameterExtendsObjectInspection.java
+++ b/java/java-analysis-impl/src/com/siyeh/ig/style/TypeParameterExtendsObjectInspection.java
@@ -15,6 +15,7 @@
*/
package com.siyeh.ig.style;
+import com.intellij.codeInsight.NullableNotNullManager;
import com.intellij.codeInspection.LocalQuickFix;
import com.intellij.codeInspection.options.OptPane;
import com.intellij.modcommand.ModPsiUpdater;
@@ -22,11 +23,13 @@ import com.intellij.modcommand.PsiUpdateModCommandQuickFix;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.intellij.psi.tree.IElementType;
+import com.intellij.psi.util.PsiTreeUtil;
import com.siyeh.InspectionGadgetsBundle;
import com.siyeh.ig.BaseInspection;
import com.siyeh.ig.BaseInspectionVisitor;
import com.siyeh.ig.psiutils.TypeUtils;
import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
import static com.intellij.codeInspection.options.OptPane.checkbox;
import static com.intellij.codeInspection.options.OptPane.pane;
@@ -135,7 +138,6 @@ public final class TypeParameterExtendsObjectInspection extends BaseInspection {
registerError(nameIdentifier, Integer.valueOf(1));
}
-
@Override
public void visitTypeElement(@NotNull PsiTypeElement typeElement) {
super.visitTypeElement(typeElement);
@@ -154,11 +156,29 @@ public final class TypeParameterExtendsObjectInspection extends BaseInspection {
if ((ignoreAnnotatedObject && extendsBound.hasAnnotations()) || !TypeUtils.isJavaLangObject(extendsBound.getType())) {
return;
}
+ if (ignoreAnnotatedObject && hasContainerAnnotations(PsiTreeUtil.getParentOfType(typeElement, PsiModifierListOwner.class))) return;
final PsiElement firstChild = typeElement.getFirstChild();
if (firstChild == null) {
return;
}
registerError(firstChild, Integer.valueOf(2));
}
+
+ /**
+ * If there is a container {@code @NullMarked} annotation, then {@code >} means {@code extends @Nullable Object>}
+ * but {@code extends Object>} mean {@code extends @NonNull Object>}.
+ * So, in this case {@code extends Object} changes the behavior.
+ * There is a case when we can delete it:
+ * {@code extends @Nullable Object>}, but it seems it is better to preserve it because it makes code easier to understand
+ * @return if there is a container annotation on the given element
+ */
+ private static boolean hasContainerAnnotations(@Nullable PsiModifierListOwner modifierListOwner) {
+ if(modifierListOwner == null) return false;
+ NullableNotNullManager manager = NullableNotNullManager.getInstance(modifierListOwner.getProject());
+ if (manager != null && manager.findContainerAnnotation(modifierListOwner) != null) {
+ return true;
+ }
+ return false;
+ }
}
}
\ No newline at end of file
diff --git a/java/java-tests/testData/ig/com/siyeh/igtest/style/type_parameter_extends_object/TypeParameterExtendsObjectWithContainerAnnotation.java b/java/java-tests/testData/ig/com/siyeh/igtest/style/type_parameter_extends_object/TypeParameterExtendsObjectWithContainerAnnotation.java
new file mode 100644
index 000000000000..2e87d544a8fd
--- /dev/null
+++ b/java/java-tests/testData/ig/com/siyeh/igtest/style/type_parameter_extends_object/TypeParameterExtendsObjectWithContainerAnnotation.java
@@ -0,0 +1,17 @@
+import org.jspecify.annotations.NullMarked;
+
+class TypeParameterExtendsObjectWithContainerAnnotation {
+ @NullMarked
+ interface SuperSuper {
+ Lib> t();
+
+ void checkNeverNull(Lib extends Object> lib);
+ }
+}
+
+@NullMarked
+final class Inner1<T extends Object> {
+}
+
+class Lib {
+}
\ No newline at end of file
diff --git a/java/java-tests/testSrc/com/siyeh/ig/style/TypeParameterExtendsObjectInspectionTest.java b/java/java-tests/testSrc/com/siyeh/ig/style/TypeParameterExtendsObjectInspectionTest.java
index 6bfd4cd2ac95..4d2b67803902 100644
--- a/java/java-tests/testSrc/com/siyeh/ig/style/TypeParameterExtendsObjectInspectionTest.java
+++ b/java/java-tests/testSrc/com/siyeh/ig/style/TypeParameterExtendsObjectInspectionTest.java
@@ -6,6 +6,7 @@ package com.siyeh.ig.style;
import com.intellij.codeInspection.InspectionProfileEntry;
import com.intellij.testFramework.LightProjectDescriptor;
import com.siyeh.ig.LightJavaInspectionTestCase;
+import org.intellij.lang.annotations.Language;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -27,6 +28,20 @@ public class TypeParameterExtendsObjectInspectionTest extends LightJavaInspectio
doTest();
}
+ public void testTypeParameterExtendsObjectWithContainerAnnotation() {
+ final TypeParameterExtendsObjectInspection inspection = getTypeParameterExtendsObjectInspection(true);
+ myFixture.enableInspections(inspection);
+ @Language("JAVA") String nullMarked =
+ """
+ package org.jspecify.annotations;
+ import java.lang.annotation.*;
+ @Target({ElementType.TYPE, ElementType.METHOD, ElementType.MODULE})
+ public @interface NullMarked {}""";
+ myFixture.addClass(nullMarked);
+
+ doTest();
+ }
+
public void testTypeParameterExtendsObjectIgnoreAnnotated() {
final TypeParameterExtendsObjectInspection inspection = getTypeParameterExtendsObjectInspection(true);
myFixture.enableInspections(inspection);