[java-inspections] IDEA-380532 IJ-CR-181243 Jspecify. False positive. Warning about a wildcard, extending Object

- make it more precise. Only for non-unknown places

GitOrigin-RevId: 830a59453f7f4264c0d530e816d5360e99ac5e52
This commit is contained in:
Mikhail Pyltsin
2025-11-04 17:45:24 +00:00
committed by intellij-monorepo-bot
parent f84482862b
commit 4345b37bae
3 changed files with 23 additions and 7 deletions
@@ -15,6 +15,8 @@
*/
package com.siyeh.ig.style;
import com.intellij.codeInsight.Nullability;
import com.intellij.codeInsight.NullabilityAnnotationInfo;
import com.intellij.codeInsight.NullableNotNullManager;
import com.intellij.codeInspection.LocalQuickFix;
import com.intellij.codeInspection.options.OptPane;
@@ -23,7 +25,6 @@ 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;
@@ -156,7 +157,7 @@ public final class TypeParameterExtendsObjectInspection extends BaseInspection {
if ((ignoreAnnotatedObject && extendsBound.hasAnnotations()) || !TypeUtils.isJavaLangObject(extendsBound.getType())) {
return;
}
if (ignoreAnnotatedObject && hasContainerAnnotations(PsiTreeUtil.getParentOfType(typeElement, PsiModifierListOwner.class))) return;
if (ignoreAnnotatedObject && hasTypeContainerAnnotations(typeElement)) return;
final PsiElement firstChild = typeElement.getFirstChild();
if (firstChild == null) {
return;
@@ -172,11 +173,14 @@ public final class TypeParameterExtendsObjectInspection extends BaseInspection {
* {@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;
private static boolean hasTypeContainerAnnotations(@Nullable PsiTypeElement typeElement) {
if (typeElement == null) return false;
NullableNotNullManager manager = NullableNotNullManager.getInstance(typeElement.getProject());
if (manager != null) {
NullabilityAnnotationInfo nullability = manager.findDefaultTypeUseNullability(typeElement);
if (nullability != null && nullability.getNullability() != Nullability.UNKNOWN) {
return true;
}
}
return false;
}
@@ -1,4 +1,5 @@
import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.NullUnmarked;
class TypeParameterExtendsObjectWithContainerAnnotation {
@NullMarked
@@ -6,6 +7,9 @@ class TypeParameterExtendsObjectWithContainerAnnotation {
Lib<?> t();
void checkNeverNull(Lib<? extends Object> lib);
@NullUnmarked
void checkNeverNull2(Lib<<warning descr="Wildcard type argument '?' explicitly extends 'java.lang.Object'">?</warning> extends Object> lib);
}
}
@@ -39,6 +39,14 @@ public class TypeParameterExtendsObjectInspectionTest extends LightJavaInspectio
public @interface NullMarked {}""";
myFixture.addClass(nullMarked);
@Language("JAVA") String nullUnmarked =
"""
package org.jspecify.annotations;
import java.lang.annotation.*;
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface NullUnmarked {}""";
myFixture.addClass(nullUnmarked);
doTest();
}