IJ-CR-181707 [java-inspections] IDEA-380526 Jspecify. False positive. Non-null type argument is expected for Array type

- simplify context

GitOrigin-RevId: 7eecfc2018d6156369dce578db5316d5b58b7a82
This commit is contained in:
Mikhail Pyltsin
2025-11-10 20:27:13 +00:00
committed by intellij-monorepo-bot
parent 052e5c08bc
commit 8e5e11275a
6 changed files with 42 additions and 138 deletions
@@ -22,7 +22,7 @@ public class PsiArrayType extends PsiType.Stub implements JvmArrayType {
private final PsiType myComponentType;
TypeNullability myNullability;
@Nullable
final PsiTypeElementPointer myElementPointer;
final PsiModifierListOwner myContainerNullabilityContext;
public PsiArrayType(@NotNull PsiType componentType) {
this(componentType, TypeAnnotationProvider.EMPTY);
@@ -39,11 +39,11 @@ public class PsiArrayType extends PsiType.Stub implements JvmArrayType {
PsiArrayType(@NotNull PsiType componentType,
@NotNull TypeAnnotationProvider provider,
@Nullable TypeNullability nullability,
@Nullable PsiTypeElementPointer elememtPointer) {
@Nullable PsiModifierListOwner containerNullabilityContext) {
super(provider);
myComponentType = componentType;
myNullability = nullability;
myElementPointer = elememtPointer;
myContainerNullabilityContext = containerNullabilityContext;
}
@Override
@@ -131,20 +131,19 @@ public class PsiArrayType extends PsiType.Stub implements JvmArrayType {
/**
* Creates a new array type instance with the specified nullable container nullability.
*
* @param elementPointer the PSI element pointer representing the context, or null if no specific context is required.
* @param containerNullabilityContext the PSI element pointer representing the context, or null if no specific context is required.
* @return a new instance of {@link PsiType} with the specified nullable container nullability.
*/
@ApiStatus.Experimental
@NotNull
public PsiType withContainerNullability(@Nullable PsiTypeElementPointer elementPointer) {
if (elementPointer == null) return this;
if (elementPointer == myElementPointer) return this;
return new PsiArrayType(myComponentType, getAnnotationProvider(), myNullability, elementPointer);
public PsiType withContainerNullability(@Nullable PsiModifierListOwner containerNullabilityContext) {
if (containerNullabilityContext == myContainerNullabilityContext) return this;
return new PsiArrayType(myComponentType, getAnnotationProvider(), myNullability, containerNullabilityContext);
}
@ApiStatus.Experimental
@Nullable
static TypeNullability getContainerNullability(@NotNull PsiTypeElement psiContext) {
static TypeNullability getContainerNullability(@NotNull PsiElement psiContext) {
Project project = psiContext.getProject();
if (project.isDefault()) return null;
NullableNotNullManager manager = NullableNotNullManager.getInstance(project);
@@ -163,22 +162,20 @@ public class PsiArrayType extends PsiType.Stub implements JvmArrayType {
@ApiStatus.Experimental
@NotNull
public PsiType withContainerNullability(@Nullable PsiArrayType arrayType) {
if (arrayType == null) return this;
if (arrayType.myElementPointer == myElementPointer) return this;
return new PsiArrayType(myComponentType, getAnnotationProvider(), myNullability, arrayType.myElementPointer);
if (arrayType == null && myContainerNullabilityContext == null) return this;
if (arrayType != null && arrayType.myContainerNullabilityContext == myContainerNullabilityContext) return this;
return new PsiArrayType(myComponentType, getAnnotationProvider(), myNullability,
arrayType != null ? arrayType.myContainerNullabilityContext : null);
}
@Override
public @NotNull TypeNullability getNullability() {
if (myNullability == null) {
TypeNullability nullability = JavaTypeNullabilityUtil.getNullabilityFromAnnotations(getAnnotations());
if (nullability == TypeNullability.UNKNOWN && myElementPointer != null) {
PsiTypeElement element = myElementPointer.retrieveElement();
if (element != null) {
TypeNullability containerNullability = getContainerNullability(element);
if (containerNullability != null) {
nullability = containerNullability;
}
if (nullability == TypeNullability.UNKNOWN && myContainerNullabilityContext != null) {
TypeNullability containerNullability = getContainerNullability(myContainerNullabilityContext);
if (containerNullability != null) {
nullability = containerNullability;
}
}
myNullability = nullability;
@@ -193,7 +190,7 @@ public class PsiArrayType extends PsiType.Stub implements JvmArrayType {
*/
@Override
public @NotNull PsiArrayType withNullability(@NotNull TypeNullability nullability) {
return new PsiArrayType(getComponentType(), getAnnotationProvider(), nullability, myElementPointer);
return new PsiArrayType(getComponentType(), getAnnotationProvider(), nullability, myContainerNullabilityContext);
}
@Override
@@ -25,8 +25,8 @@ public class PsiEllipsisType extends PsiArrayType {
private PsiEllipsisType(@NotNull PsiType componentType,
@NotNull TypeAnnotationProvider provider,
@Nullable TypeNullability nullability,
@Nullable PsiTypeElementPointer typeElementPointer) {
super(componentType, provider, nullability, typeElementPointer);
@Nullable PsiModifierListOwner containerNullabilityOwner) {
super(componentType, provider, nullability, containerNullabilityOwner);
}
@Override
@@ -52,23 +52,23 @@ public class PsiEllipsisType extends PsiArrayType {
@NotNull
@Override
public PsiType withContainerNullability(@Nullable PsiTypeElementPointer elementPointer) {
if (elementPointer == null) return this;
if (elementPointer == myElementPointer) return this;
return new PsiEllipsisType(getComponentType(), getAnnotationProvider(), myNullability, elementPointer);
public PsiType withContainerNullability(@Nullable PsiModifierListOwner containerNullabilityContext) {
if (containerNullabilityContext == myContainerNullabilityContext) return this;
return new PsiEllipsisType(getComponentType(), getAnnotationProvider(), myNullability, containerNullabilityContext);
}
@NotNull
@Override
public PsiType withContainerNullability(@Nullable PsiArrayType arrayType) {
if (arrayType == null) return this;
if (arrayType.myElementPointer == myElementPointer) return this;
return new PsiEllipsisType(getComponentType(), getAnnotationProvider(), myNullability, arrayType.myElementPointer);
if (arrayType == null && myContainerNullabilityContext == null) return this;
if (arrayType != null && arrayType.myContainerNullabilityContext == myContainerNullabilityContext) return this;
return new PsiEllipsisType(getComponentType(), getAnnotationProvider(), myNullability,
arrayType != null ? arrayType.myContainerNullabilityContext : null);
}
@Override
public @NotNull PsiEllipsisType withNullability(@NotNull TypeNullability nullability) {
return new PsiEllipsisType(getComponentType(), getAnnotationProvider(), nullability, this.myElementPointer);
return new PsiEllipsisType(getComponentType(), getAnnotationProvider(), nullability, this.myContainerNullabilityContext);
}
/**
@@ -1,22 +0,0 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.psi;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@ApiStatus.Experimental
public interface PsiTypeElementPointer {
@Nullable
PsiTypeElement retrieveElement();
static PsiTypeElementPointer constant(@NotNull PsiTypeElement ref) {
return new PsiTypeElementPointer() {
@Override
public @NotNull PsiTypeElement retrieveElement() {
return ref;
}
};
}
}
@@ -10,6 +10,7 @@ import com.intellij.psi.impl.cache.ExternalTypeAnnotationContainer;
import com.intellij.psi.impl.cache.TypeAnnotationContainer;
import com.intellij.psi.impl.cache.TypeInfo;
import com.intellij.psi.impl.source.PsiClassReferenceType;
import com.intellij.psi.impl.source.PsiTypeElementImpl;
import com.intellij.psi.impl.source.SourceTreeToPsiMap;
import com.intellij.psi.impl.source.tree.JavaElementType;
import com.intellij.psi.impl.source.tree.TreeElement;
@@ -189,9 +190,9 @@ public class ClsTypeElementImpl extends ClsElementImpl implements PsiTypeElement
PsiType type = deepestChild.getType();
for (int i = depth - 1; i >= 0; i--) {
if (i == 0 && isVarArgs()) {
type = new PsiEllipsisType(type).withContainerNullability(PsiTypeElementPointer.constant(deepestChild));
type = new PsiEllipsisType(type).withContainerNullability(PsiTypeElementImpl.findContainerNullabilityContext(deepestChild));
} else {
type = type.createArrayType().withContainerNullability(PsiTypeElementPointer.constant(deepestChild));
type = type.createArrayType().withContainerNullability(PsiTypeElementImpl.findContainerNullabilityContext(deepestChild));
}
type = type.annotate(containers.get(i).getProvider(this));
}
@@ -3,15 +3,12 @@ package com.intellij.psi.impl.source;
import com.intellij.codeInsight.daemon.impl.analysis.JavaGenericsUtil;
import com.intellij.lang.ASTNode;
import com.intellij.openapi.diagnostic.Attachment;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.RecursionGuard;
import com.intellij.openapi.util.RecursionManager;
import com.intellij.psi.*;
import com.intellij.psi.augment.PsiAugmentProvider;
import com.intellij.psi.impl.PsiImplUtil;
import com.intellij.psi.impl.PsiJavaParserFacadeImpl;
import com.intellij.psi.impl.compiled.ClsTypeElementImpl;
import com.intellij.psi.impl.source.tree.*;
import com.intellij.psi.scope.PsiScopeProcessor;
import com.intellij.psi.tree.IElementType;
@@ -30,8 +27,6 @@ import java.util.List;
public class PsiTypeElementImpl extends CompositePsiElement implements PsiTypeElement {
private static final Logger LOG = Logger.getInstance(PsiTypeElementImpl.class);
public PsiTypeElementImpl() {
this(JavaElementType.TYPE);
}
@@ -166,8 +161,8 @@ public class PsiTypeElementImpl extends CompositePsiElement implements PsiTypeEl
for (int i = providers.size() - 1; i >= 0; i--) {
TypeAnnotationProvider provider = providers.get(i);
result = ellipsis && i == 0 ?
new PsiEllipsisType(result, provider).withContainerNullability(createTypeElementPointer(this)) :
new PsiArrayType(result, provider).withContainerNullability(createTypeElementPointer(this));
new PsiEllipsisType(result, provider).withContainerNullability(findContainerNullabilityContext(this)) :
new PsiArrayType(result, provider).withContainerNullability(findContainerNullabilityContext(this));
}
providers.clear();
return result;
@@ -519,82 +514,15 @@ public class PsiTypeElementImpl extends CompositePsiElement implements PsiTypeEl
}
@ApiStatus.Experimental
@NotNull
public static PsiTypeElementPointer createTypeElementPointer(@NotNull PsiTypeElement typeElement) {
if (typeElement instanceof ClsTypeElementImpl) {
return PsiTypeElementPointer.constant(typeElement);
}
PsiElement parent = getAnchorParent(typeElement);
if ((parent instanceof JavaStubPsiElement) && (parent instanceof PsiMethod || parent instanceof PsiVariable)) {
PsiModifierListOwner owner = (PsiModifierListOwner)parent;
PsiTypeElement ownerType =
parent instanceof PsiMethod ? ((PsiMethod)parent).getReturnTypeElement() : ((PsiVariable)parent).getTypeElement();
if (ownerType == null) return PsiTypeElementPointer.constant(typeElement);
int[] pathFromRoot = getPathFromRoot(ownerType, typeElement);
if (pathFromRoot == null) return PsiTypeElementPointer.constant(typeElement);
return computeTypeElementPointerFromTypeOwner(owner, pathFromRoot, new WeakReference<>(typeElement));
}
return PsiTypeElementPointer.constant(typeElement);
}
private static @NotNull PsiTypeElementPointer computeTypeElementPointerFromTypeOwner(@NotNull PsiModifierListOwner owner,
int @NotNull [] root,
@NotNull WeakReference<PsiTypeElement> reference) {
return new PsiTypeElementPointer() {
@Override
public @Nullable PsiTypeElement retrieveElement() {
PsiTypeElement element = reference.get();
if (element != null && element.isValid()) return element;
if (!owner.isValid()) return null;
PsiElement parentTypeElement =
owner instanceof PsiMethod ? ((PsiMethod)owner).getReturnTypeElement() : ((PsiVariable)owner).getTypeElement();
if (parentTypeElement == null) return null;
PsiElement typeElement = parentTypeElement;
for (int i : root) {
List<@NotNull PsiElement> filtered = ContainerUtil.filter(typeElement.getChildren(),
t -> t instanceof PsiTypeElement ||
t instanceof PsiJavaCodeReferenceElement ||
t instanceof PsiReferenceParameterList);
if (i >= filtered.size()) return null;
typeElement = filtered.get(i);
}
if (typeElement instanceof PsiTypeElement) {
return (PsiTypeElement)typeElement;
}
LOG.error("Can't decode PsiTypeElement with indexes",
new Attachment("memberType.txt", parentTypeElement.getText() + "\n" + Arrays.toString(root)));
return null;
@Nullable
public static PsiModifierListOwner findContainerNullabilityContext(@NotNull PsiTypeElement typeElement) {
PsiElement parent = typeElement.getContext();
while (parent != null) {
if(parent instanceof PsiModifierListOwner) {
return (PsiModifierListOwner)parent;
}
};
}
private static int @Nullable [] getPathFromRoot(@NotNull PsiTypeElement targetParent, @NotNull PsiTypeElement child) {
IntList result = new IntArrayList();
PsiElement currentChild = child;
while (true) {
if (currentChild == targetParent) {
return result.toIntArray();
}
PsiElement parent = currentChild.getParent();
if (parent instanceof PsiTypeElement ||
parent instanceof PsiJavaCodeReferenceElement ||
parent instanceof PsiReferenceParameterList) {
List<PsiElement> psiTypeElementChildren =
ContainerUtil.filter(parent.getChildren(),
t -> t instanceof PsiTypeElement ||
t instanceof PsiJavaCodeReferenceElement ||
t instanceof PsiReferenceParameterList);
int index = psiTypeElementChildren.indexOf(currentChild);
result.add(0, index);
currentChild = parent;
continue;
}
LOG.error("Can't code PsiTypeElement with indexes",
new Attachment("memberType.txt", targetParent.getText() + "\n" + child.getText()));
return null;
parent = parent.getContext();
}
return null;
}
}
@@ -45,8 +45,8 @@ public final class JavaSharedImplUtil {
if (allAnnotations == null) return null;
for (int i = 0, size = allAnnotations.size(); i < size; i++) {
type = ((ellipsisType && i == size - 1) ?
new PsiEllipsisType(type).withContainerNullability(PsiTypeElementImpl.createTypeElementPointer(typeElement) ) :
type.createArrayType().withContainerNullability(PsiTypeElementImpl.createTypeElementPointer(typeElement)))
new PsiEllipsisType(type).withContainerNullability(PsiTypeElementImpl.findContainerNullabilityContext(typeElement) ) :
type.createArrayType().withContainerNullability(PsiTypeElementImpl.findContainerNullabilityContext(typeElement)))
.annotate(TypeAnnotationProvider.Static.create(allAnnotations.get(i)));
}