From 8e5e11275a96941de9473703cf86fbd2412bbd79 Mon Sep 17 00:00:00 2001 From: Mikhail Pyltsin Date: Mon, 10 Nov 2025 18:52:46 +0100 Subject: [PATCH] IJ-CR-181707 [java-inspections] IDEA-380526 Jspecify. False positive. Non-null type argument is expected for Array type - simplify context GitOrigin-RevId: 7eecfc2018d6156369dce578db5316d5b58b7a82 --- .../src/com/intellij/psi/PsiArrayType.java | 37 ++++---- .../src/com/intellij/psi/PsiEllipsisType.java | 20 ++-- .../intellij/psi/PsiTypeElementPointer.java | 22 ----- .../psi/impl/compiled/ClsTypeElementImpl.java | 5 +- .../psi/impl/source/PsiTypeElementImpl.java | 92 ++----------------- .../impl/source/tree/JavaSharedImplUtil.java | 4 +- 6 files changed, 42 insertions(+), 138 deletions(-) delete mode 100644 java/java-psi-api/src/com/intellij/psi/PsiTypeElementPointer.java diff --git a/java/java-psi-api/src/com/intellij/psi/PsiArrayType.java b/java/java-psi-api/src/com/intellij/psi/PsiArrayType.java index 17e1dd4db1d9..d04fc587c820 100644 --- a/java/java-psi-api/src/com/intellij/psi/PsiArrayType.java +++ b/java/java-psi-api/src/com/intellij/psi/PsiArrayType.java @@ -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 diff --git a/java/java-psi-api/src/com/intellij/psi/PsiEllipsisType.java b/java/java-psi-api/src/com/intellij/psi/PsiEllipsisType.java index 28a78029f7d8..46cdba8eeb1c 100644 --- a/java/java-psi-api/src/com/intellij/psi/PsiEllipsisType.java +++ b/java/java-psi-api/src/com/intellij/psi/PsiEllipsisType.java @@ -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); } /** diff --git a/java/java-psi-api/src/com/intellij/psi/PsiTypeElementPointer.java b/java/java-psi-api/src/com/intellij/psi/PsiTypeElementPointer.java deleted file mode 100644 index 48ef3b843eb3..000000000000 --- a/java/java-psi-api/src/com/intellij/psi/PsiTypeElementPointer.java +++ /dev/null @@ -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; - } - }; - } -} diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsTypeElementImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsTypeElementImpl.java index 60cc3b1c839a..1ae76d4299ae 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsTypeElementImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsTypeElementImpl.java @@ -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)); } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiTypeElementImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiTypeElementImpl.java index 5f3d0056d40e..80ed3e96c030 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiTypeElementImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiTypeElementImpl.java @@ -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 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 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; } } \ No newline at end of file diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/JavaSharedImplUtil.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/JavaSharedImplUtil.java index 234de5aaadf3..b0daf76023f7 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/JavaSharedImplUtil.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/JavaSharedImplUtil.java @@ -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))); }